I have:
Device: Samsung Galaxy Watch Active (SM-R500);
Tizen version (API): 4.0;
Knox Tizen SDK for Wearables version: 2.4;
On the Knox Partner portal I have found active KPE Standart key and then implemented it into my code.
I get the privilege to set time functions (http://developer.samsung.com/tizen/privilege/mdm.datetime) with ppm_check_permission function:
...
const char *privileges[] =
{
"http://tizen.org/privilege/mediastorage",
"http://tizen.org/privilege/location",
"http://tizen.org/privilege/healthinfo",
"http://developer.samsung.com/tizen/privilege/mdm.admin",
"http://developer.samsung.com/tizen/privilege/mdm.datetime",
"http://developer.samsung.com/tizen/privilege/mdm.location",
};
...
static void _ppm_request_response_cb(ppm_call_cause_e cause, ppm_request_result_e result, const char *privilege, void *user_data)
{
if (cause == PRIVACY_PRIVILEGE_MANAGER_CALL_CAUSE_ERROR)
{
LOG_PRINT(DLOG_DEBUG, "Error request response!");
/* Log and handle errors */
return;
}
switch (result)
{
case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_ALLOW_FOREVER:
/* Update UI and start accessing protected functionality */
LOG_PRINT(DLOG_DEBUG, "PPM request result: allow forever");
break;
case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_DENY_FOREVER:
/* Show a message and terminate the application */
LOG_PRINT(DLOG_DEBUG, "PPM request result: deny forever");
ui_app_exit();
break;
case PRIVACY_PRIVILEGE_MANAGER_REQUEST_RESULT_DENY_ONCE:
/* Show a message with explanation */
LOG_PRINT(DLOG_DEBUG, "PPM request result: deny once");
ui_app_exit();
break;
}
}
...
static bool _create_cb(void *data)
{
int i = 0;
int ret = PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
ppm_check_result_e result = PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ALLOW;
int size = sizeof(privileges) / sizeof(char *);
setlocale(LC_ALL, "en_US.UTF-8");
for (i = 0; i < size; i++)
{
ret = ppm_check_permission(privileges[i], &result);
if (ret == PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE)
{
switch (result)
{
case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ALLOW:
LOG_PRINT(DLOG_DEBUG, "PPM request response: allow");
break;
case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY:
LOG_PRINT(DLOG_DEBUG, "PPM error request response: deny");
ui_app_exit();
break;
case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ASK:
ret = ppm_request_permission(privileges[i], _ppm_request_response_cb, NULL);
LOG_PRINT(DLOG_DEBUG, "[ppm_request_permission] return %d", (int)ret);
break;
}
}
}
file_logger_init(pfl, PATH_LOGS, CURRENT_VERSION, LOGGER_ROTATE_BY_SIZE | LOGGER_ROTATE_PER_HOUR, 8);
if (!g_init())
{
LOG_PRINT(DLOG_ERROR, "GNSS is not working!");
}
me_init();
gui_create_base();
c_set_state(ST_WIZARD_STEP1);
elm_run();
return true;
}
...
int main(int argc, char *argv[])
{
int ret = 0;
app_data_t app_data = { 0, };
ui_app_lifecycle_callback_s event_callback = { 0, };
app_event_handler_h handlers[5] = { NULL, };
pfl = &fl;
feedback_initialize();
event_callback.create = _create_cb;
event_callback.terminate = _terminate_cb;
event_callback.pause = _pause_cb;
event_callback.resume = _resume_cb;
event_callback.app_control = _app_control_cb;
device_add_callback(DEVICE_CALLBACK_BATTERY_CHARGING, _device_changed_cb, NULL);
ui_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY],
APP_EVENT_LOW_BATTERY, _app_event_low_battery_cb, &app_data);
ui_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY],
APP_EVENT_LOW_MEMORY, _app_event_low_memory_cb, &app_data);
ui_app_add_event_handler(&handlers[APP_EVENT_DEVICE_ORIENTATION_CHANGED],
APP_EVENT_DEVICE_ORIENTATION_CHANGED, _app_event_device_orientation_changed_cb, &app_data);
ui_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED],
APP_EVENT_LANGUAGE_CHANGED, _app_event_language_changed_cb, &app_data);
ui_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED],
APP_EVENT_REGION_FORMAT_CHANGED, _app_event_region_format_changed_cb, &app_data);
ret = ui_app_main(argc, argv, &event_callback, &app_data);
if (ret != APP_ERROR_NONE)
{
LOG_PRINT(DLOG_ERROR, "[ui_app_main] return %d.", ret);
}
return ret;
}
I try set time with next code:
#include <logger_ext.h>
#include "mdm_ext.h"
#include "main.h"
#include <mdm.h>
#include <knox_custom.h>
#include <tizen.h>
#include <app_preference.h>
/* Registration keys */
#ifndef KEY
#define KEY "KLM09-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"
#endif
static const char *old_licenses[] =
{
"KLM09-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
"KLM09-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
"KLM06-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
};
static void _date_time_cb(int oper, void *cb_data, void *user_data);
static void _mdm_client_cb(int oper, void *cb_data, void *user_data);
static void _date_time_cb(int oper, void *cb_data, void *user_data)
{
/*mdm_license_callback_t *ldata = (mdm_license_callback_t *)cb_data;
switch (oper)
{
case MDM_CB_LICENSE_DEACTIVATE_KNOX:
break;
default:
break;
}*/
}
static void _mdm_client_cb(int oper, void *cb_data, void *user_data)
{
if (!cb_data)
{
LOG_PRINT(DLOG_DEBUG, "cb_data == NULL");
return;
}
const mdm_license_callback_t *ldata = (mdm_license_callback_t *) cb_data;
if (!ldata || !ldata->license_info)
{
LOG_PRINT(DLOG_DEBUG, "ldata == NULL");
return;
}
switch (oper)
{
case MDM_CB_LICENSE_ACTIVATE:
if (ldata->license_info->error_code == 0)
{
LOG_PRINT(DLOG_INFO, "Success");
}
else
{
LOG_PRINT(DLOG_ERROR, "Fail: %s", ldata->license_info->error_desc);
}
break;
case MDM_CB_LICENSE_ACTIVATE_KNOX:
if (ldata->license_info->error_code == 0)
{
LOG_PRINT(DLOG_INFO, "Success");
}
else
{
LOG_PRINT(DLOG_ERROR, "Fail: %s", ldata->license_info->error_desc);
}
break;
case MDM_CB_LICENSE_DEACTIVATE_KNOX:
if (ldata->license_info->error_code == 0)
{
LOG_PRINT(DLOG_INFO, "Success");
}
else
{
LOG_PRINT(DLOG_ERROR, "Fail: %s", ldata->license_info->error_desc);
}
break;
case MDM_CB_LICENSE_VALIDATE_RESULT:
if (ldata->license_info->error_code == 0)
{
LOG_PRINT(DLOG_INFO, "Success");
}
else
{
LOG_PRINT(DLOG_ERROR, "Fail: %s", ldata->license_info->error_desc);
}
break;
case MDM_CB_LICENSE_KNOX_VALIDATE_RESULT:
if (ldata->license_info->error_code == 0)
{
LOG_PRINT(DLOG_INFO, "Success");
}
else
{
LOG_PRINT(DLOG_ERROR, "Fail: %s", ldata->license_info->error_desc);
}
break;
default:
break;
}
}
void me_init(void)
{
int ret = MDM_RESULT_SUCCESS;
mdm_data_t *mdm_data = NULL;
mdm_result_t mdm_result = MDM_RESULT_SUCCESS;
mdm_status_t mdm_status = MDM_TRUE;
int size = sizeof(old_licenses) / sizeof(char *);
int i = 0;
ret = mdm_register_client(PACKAGE);
switch (ret)
{
case MDM_RESULT_SERVICE_NOT_ENABLED:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_SERVICE_NOT_ENABLED");
break;
case MDM_RESULT_ACCESS_DENIED:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_ACCESS_DENIED");
break;
case MDM_RESULT_INVALID_PARAM:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_INVALID_PARAM");
break;
case MDM_RESULT_NOT_SUPPORTED:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_NOT_SUPPORTED");
break;
case MDM_RESULT_FAIL:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_FAIL");
break;
case MDM_RESULT_SUCCESS:
LOG_PRINT(DLOG_INFO, "MDM_RESULT_SUCCESS");
break;
case MDM_NOT_AN_OWNER:
LOG_PRINT(DLOG_ERROR, "MDM_NOT_AN_OWNER");
break;
default:
LOG_PRINT(DLOG_ERROR, "[mdm_register_client] return %d", ret);
break;
}
mdm_result = mdm_get_service();
if (mdm_result != MDM_RESULT_SUCCESS)
{
LOG_PRINT(DLOG_ERROR, "[mdm_get_service] return %d", mdm_result);
mdm_release_service();
return;
}
ret = mdm_register_client_callback(MDM_LICENSE_CB, _mdm_client_cb, NULL, NULL);
if (ret != MDM_RESULT_SUCCESS)
{
LOG_PRINT(DLOG_ERROR, "[mdm_register_client_callback] return %d", ret);
mdm_release_service();
return;
}
for (i = 0; i < size; i++)
{
mdm_data = mdm_deactivate_knox_license(PACKAGE, old_licenses[i]);
if (mdm_data != NULL)
{
mdm_free_data(mdm_data);
}
else
{
LOG_PRINT(DLOG_ERROR, "[mdm_deactivate_knox_license] return NULL");
}
}
mdm_data = mdm_activate_knox_license(PACKAGE, KEY);
if (mdm_data->ret == MDM_RESULT_SUCCESS)
{
LOG_PRINT(DLOG_INFO, "License Activated");
}
else
{
LOG_PRINT(DLOG_ERROR, "[mdm_activate_knox_license] return %d", (int)mdm_data->ret);
}
mdm_free_data(mdm_data);
mdm_status = mdm_is_client_registered(PACKAGE);
if (mdm_status != MDM_TRUE)
{
LOG_PRINT(DLOG_ERROR, "[mdm_is_client_registered] return %d", (int)mdm_status);
mdm_data = mdm_activate_knox_license(PACKAGE, KEY);
if (mdm_data->ret == MDM_RESULT_SUCCESS)
{
LOG_PRINT(DLOG_INFO, "MDM_RESULT_SUCCESS");
}
else
{
LOG_PRINT(DLOG_ERROR, "[mdm_activate_knox_license] return %d", (int)mdm_data->ret);
}
mdm_free_data(mdm_data);
}
else
{
LOG_PRINT(DLOG_INFO, "Client Registered");
}
mdm_release_service();
}
void me_disable_automatic_time(void)
{
int ret = MDM_RESULT_SUCCESS;
mdm_result_t mdm_result = MDM_RESULT_SUCCESS;
ret = mdm_register_client(PACKAGE);
switch (ret)
{
case MDM_RESULT_SERVICE_NOT_ENABLED:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_SERVICE_NOT_ENABLED");
break;
case MDM_RESULT_ACCESS_DENIED:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_ACCESS_DENIED");
break;
case MDM_RESULT_INVALID_PARAM:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_INVALID_PARAM");
break;
case MDM_RESULT_NOT_SUPPORTED:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_NOT_SUPPORTED");
break;
case MDM_RESULT_FAIL:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_FAIL");
break;
case MDM_RESULT_SUCCESS:
LOG_PRINT(DLOG_INFO, "MDM_RESULT_SUCCESS");
break;
case MDM_NOT_AN_OWNER:
LOG_PRINT(DLOG_ERROR, "MDM_NOT_AN_OWNER");
break;
default:
LOG_PRINT(DLOG_ERROR, "[mdm_register_client] return %d", ret);
break;
}
mdm_result = mdm_get_service();
if (mdm_result != MDM_RESULT_SUCCESS)
{
LOG_PRINT(DLOG_ERROR, "[mdm_get_service] return %d", mdm_result);
mdm_release_service();
return;
}
mdm_result = mdm_set_automatic_time(MDM_FALSE);
if (mdm_result != MDM_RESULT_SUCCESS)
{
LOG_PRINT(DLOG_ERROR, "[mdm_set_automatic_time] return %d", mdm_result);
}
mdm_release_service();
}
bool me_set_date_time(int year, int month, int day, int hour, int minute, int second)
{
int _ret = MDM_RESULT_SUCCESS;
bool ret = false;
mdm_result_t res = MDM_RESULT_SUCCESS;
LOG_PRINT(DLOG_DEBUG, "-> %4d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
_ret = mdm_register_client(PACKAGE);
switch (_ret)
{
case MDM_RESULT_SERVICE_NOT_ENABLED:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_SERVICE_NOT_ENABLED");
break;
case MDM_RESULT_ACCESS_DENIED:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_ACCESS_DENIED");
break;
case MDM_RESULT_INVALID_PARAM:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_INVALID_PARAM");
break;
case MDM_RESULT_NOT_SUPPORTED:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_NOT_SUPPORTED");
break;
case MDM_RESULT_FAIL:
LOG_PRINT(DLOG_ERROR, "MDM_RESULT_FAIL");
break;
case MDM_RESULT_SUCCESS:
LOG_PRINT(DLOG_INFO, "MDM_RESULT_SUCCESS");
break;
case MDM_NOT_AN_OWNER:
LOG_PRINT(DLOG_ERROR, "MDM_NOT_AN_OWNER");
break;
default:
LOG_PRINT(DLOG_ERROR, "[mdm_register_client] return %d", ret);
break;
}
res = mdm_get_service();
if (res != MDM_RESULT_SUCCESS)
{
LOG_PRINT(DLOG_ERROR, "[mdm_get_service] return %d", (int)res);
return ret;
}
mdm_register_client_callback(MDM_DATE_TIME_CB, _date_time_cb, NULL, NULL);
res = mdm_set_date_time_change_enabled(true);
if (res != MDM_RESULT_SUCCESS)
{
mdm_release_service();
LOG_PRINT(DLOG_ERROR, "[mdm_set_date_time_change_enabled] return %d", (int)res);
return ret;
}
res = mdm_set_date_time(day, month, year, hour, minute, second);
if (res != MDM_RESULT_SUCCESS)
{
mdm_release_service();
LOG_PRINT(DLOG_ERROR, "[mdm_set_date_time] return %d", (int)res);
return ret;
}
res = mdm_set_date_time_change_enabled(false);
if (res != MDM_RESULT_SUCCESS)
{
mdm_release_service();
LOG_PRINT(DLOG_ERROR, "[mdm_set_date_time_change_enabled] return %d", (int)res);
return ret;
}
ret = true;
mdm_release_service();
LOG_PRINT(DLOG_INFO, "Time sync completed");
return ret;
}
The procedure for calling features:
...
me_init();
me_disable_automatic_time();
me_set_date_time(2020, 3, 31, 16, 54, 1);
...
MY ISSUE:
For function mdm_set_automatic_time() returned status -13 with my commercial key, but at the same time status for mdm_activate_knox_license() is MDM_RESULT_SUCCESS.
BUT it fine working and the error is not repeated for several devices, it's 2-3 out of 42 devices. For these devices, the application has been uploaded with console Knox Configure.
What kind of actions can I do wrong?
The problem was on the server side of Samsung when calculating the hash. The problem is solved.