mdmsamsung-knox

Samsung Galaxy Watch: mdm_set_automatic_time() returned status -13 and not set the time


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?


Solution

  • The problem was on the server side of Samsung when calculating the hash. The problem is solved.