/*---------------------------------------------------------------------------- * Copyright (c) TJD Technologies Co., Ltd. 2025. All rights reserved. * * Description: TjdAppStore.cpp * * Author: luziquan@ss-tjd.com * * Create: 2025-03-19 *--------------------------------------------------------------------------*/ #include "TjdAppStore.h" #include "abilityms_slite_client.h" #include "adapter.h" #include "bundlems_slite_client.h" #include "cJSON.h" #include "fs_user_common.h" #include "msg_center_customer.h" #include "sys_config.h" #include "ui_service.h" #include #include #define ENABLE_PRINT_INFO 1 #if ENABLE_PRINT_INFO #define static_print_error(...) sys_ui_log_e(__VA_ARGS__) // 错误信息打印一般常开 #define static_print_debug(...) sys_ui_log_d(__VA_ARGS__) // 调试信息打印 #else #define static_print_error(...) #define static_print_debug(...) #endif #define PKG_NAME_MAX_LENGTH 128 #define LABLE_MAX_LENGTH 128 #define VERSION_MAX_LENGTH 20 #define TJD_JS_DIR TJD_FS_DIR_JS "/" #define TJD_JSON_FILE_PATH "/system/app_list.json" #define MAX_RETRY 3 /* 是否安装完成后删除安装包 */ #define DELETE_PKG_AFTER_INSTALL 1 typedef struct { uint8_t pkgName[PKG_NAME_MAX_LENGTH]; uint8_t label[LABLE_MAX_LENGTH]; uint8_t versionName[VERSION_MAX_LENGTH]; uint8_t versionCode[VERSION_MAX_LENGTH]; } PkgUnitInfo; std::list g_pkgOperationCallbackList; #if DELETE_PKG_AFTER_INSTALL static void DeletePkgAfterInstall(const char *pkgName) { if (!pkgName) { return; } char *pkgFullName = nullptr; uint8_t len = strlen(TJD_JS_DIR) + strlen((char *)pkgName) + strlen(".bin") + 1; pkgFullName = (char *)malloc(len); if (pkgFullName != nullptr) { (void)sprintf_s(pkgFullName, len, "%s%s.bin", TJD_JS_DIR, (char *)pkgName); (void)unlink(pkgFullName); free(pkgFullName); } } #endif static void SendMsgToCallback(const uint8_t resultCode, const void *resultMessage) { if (g_pkgOperationCallbackList.size() == 0) { return; } BundleInstallMsg *installMsg = (BundleInstallMsg *)AdapterMalloc(sizeof(BundleInstallMsg)); if (installMsg == nullptr) { return; } (void)memcpy_s(installMsg, sizeof(BundleInstallMsg), resultMessage, sizeof(BundleInstallMsg)); for (auto callback : g_pkgOperationCallbackList) { callback(resultCode, installMsg); } AdapterFree(installMsg); } static void ReceiveCallback(const uint8_t resultCode, const void *resultMessage) { BundleInstallMsg *installMsg = (BundleInstallMsg *)resultMessage; if (resultCode == 0) { BundleData bundleData; memset_s(&bundleData, sizeof(BundleData), 0, sizeof(BundleData)); strncpy_s(bundleData.bundleName, BUNDLE_NAME_LEN, installMsg->bundleName, BUNDLE_NAME_LEN); static_print_debug("bms resultCode = 0x%x", resultCode); static_print_debug("bms bundleName = %s", bundleData.bundleName); if (installMsg->installState == BUNDLE_INSTALL_OK) { strncpy_s(bundleData.label, BUNDLE_PATH_LEN, installMsg->label, BUNDLE_PATH_LEN); strncpy_s(bundleData.smallIconPath, BUNDLE_PATH_LEN, installMsg->smallIconPath, BUNDLE_PATH_LEN); strncpy_s(bundleData.bigIconPath, BUNDLE_PATH_LEN, installMsg->bigIconPath, BUNDLE_PATH_LEN); SendMsgToUIService(JS_INSTALL_SUCESS_TO_UI, 0, &bundleData, sizeof(BundleData)); #if DELETE_PKG_AFTER_INSTALL /* 安装完成后删除安装包 */ DeletePkgAfterInstall(installMsg->bundleName); #endif } else if (installMsg->installState == BUNDLE_UNINSTALL_OK) { SendMsgToUIService(JS_UNINSTALL_SUCESS_TO_UI, 0, &bundleData, sizeof(BundleData)); } } else { static_print_debug("bms resultCode = 0x%x", resultCode); } SendMsgToCallback(resultCode, resultMessage); AdapterFree(installMsg); } bool TjdAppStorePkgOperation(PkgOperationType type, const char *pkgName, bool isKeepData) { bool ret = false; if (type == PKG_OPERATION_TYPE_INSTALL) { char *pkgFullName = nullptr; uint8_t len = strlen(TJD_JS_DIR) + strlen((char *)pkgName) + strlen(".bin") + 1; pkgFullName = (char *)malloc(len); if (pkgFullName != nullptr) { (void)sprintf_s(pkgFullName, len, "%s%s.bin", TJD_JS_DIR, (char *)pkgName); InstallParam installParam = {.installLocation = 1, .keepData = false}; ret = OHOS::BundleMsClient::GetInstance().Install(pkgFullName, &installParam, ReceiveCallback); free(pkgFullName); } } else if (type == PKG_OPERATION_TYPE_UNINSTALL) { StopJsApp((char *)pkgName); InstallParam installParam = {.installLocation = 1, .keepData = isKeepData}; ret = OHOS::BundleMsClient::GetInstance().Uninstall(pkgName, &installParam, ReceiveCallback); } return ret; } bool TjdAppStoreQueryPkgState(const char *pkgName, PkgState *state) { if (!pkgName || !state) { return false; } BundleInfo bundleInfo; uint8_t bundleRet = OHOS::BundleMsClient::GetInstance().GetBundleInfo(pkgName, 0, &bundleInfo); static_print_debug("GetInstallState bundleRet = 0x%x", bundleRet); if (bundleRet == 0) { ElementName *topAbility = OHOS::AbilityMsClient::GetInstance().GetTopAbility(); *state = (topAbility && strcmp(topAbility->bundleName, pkgName) == 0) ? PKG_STATE_RUNNING : PKG_STATE_INSTALLED; FreeElement(topAbility); } else { *state = PkgState::PKG_STATE_UNINSTALLED; } return true; } static bool ClearJsonToFile(void) { FILE *fp = nullptr; fp = fopen(TJD_JSON_FILE_PATH, "w+"); if (fp == NULL) { static_print_error("Failed to open file"); return false; } fclose(fp); static_print_debug("ClearJsonToFile Success"); return true; } static int SaveJsonToFile(const char *jsonStr) { if (!jsonStr) { static_print_error("Invalid JSON string"); return -1; } FILE *fp = nullptr; size_t writeSize = 0; size_t jsonLen = strlen(jsonStr); int retryCount = 0; do { fp = fopen(TJD_JSON_FILE_PATH, "w+"); if (!fp) { static_print_error("Failed to open file (attempt %d), errno=%d", retryCount + 1, errno); retryCount++; continue; } writeSize = fwrite(jsonStr, 1, jsonLen, fp); if (writeSize != jsonLen) { static_print_error("Write incomplete %zu/%zu bytes", writeSize, jsonLen); fclose(fp); return -2; } fclose(fp); static_print_debug("File saved successfully"); return 0; } while (retryCount < MAX_RETRY); static_print_error("Persistent file write failure"); return -3; } static char *ConvertToCjson(const std::vector &unitInfoList) { cJSON *rootArray = cJSON_CreateArray(); if (!rootArray) return nullptr; for (const auto &pkgInfo : unitInfoList) { cJSON *appItem = cJSON_CreateObject(); if (!appItem) continue; const char *pkgName = reinterpret_cast(pkgInfo.pkgName); const char *label = reinterpret_cast(pkgInfo.label); const char *versionName = reinterpret_cast(pkgInfo.versionName); const char *versionCode = reinterpret_cast(pkgInfo.versionCode); cJSON_AddStringToObject(appItem, "pkgName", pkgName); cJSON_AddStringToObject(appItem, "label", label); cJSON_AddStringToObject(appItem, "versionName", versionName); cJSON_AddStringToObject(appItem, "versionCode", versionCode); cJSON_AddItemToArray(rootArray, appItem); } char *jsonStr = cJSON_PrintUnformatted(rootArray); cJSON_Delete(rootArray); return jsonStr; } bool TjdAppStorePkgUpdateList(void) { BundleInfo *bundleInfos = nullptr; bool ret = false; int32_t count = 0; uint8_t bundleRet = OHOS::BundleMsClient::GetInstance().GetBundleInfos(0, &bundleInfos, &count); static_print_debug("GetBundleInfos count = %d bundleRet = 0x%x", count, bundleRet); ClearJsonToFile(); if (count == 0) { AdapterFree(bundleInfos); static_print_error("No bundle found"); return false; } std::vector unitInfoList(count); for (int32_t i = 0; i < count; i++) { (void)strncpy_s((char *)unitInfoList[i].pkgName, PKG_NAME_MAX_LENGTH, bundleInfos[i].bundleName, strlen(bundleInfos[i].bundleName)); (void)strncpy_s((char *)unitInfoList[i].label, LABLE_MAX_LENGTH, bundleInfos[i].label, strlen(bundleInfos[i].label)); (void)strncpy_s((char *)unitInfoList[i].versionName, VERSION_MAX_LENGTH, bundleInfos[i].versionName, strlen(bundleInfos[i].versionName)); sprintf((char *)unitInfoList[i].versionCode, "%d", bundleInfos[i].versionCode); static_print_debug("AppStoreGetPkgList pkgName[%d] = %s", i, unitInfoList[i].pkgName); static_print_debug("AppStoreGetPkgList lable[%d] = %s", i, unitInfoList[i].label); static_print_debug("versionCode = %d versionName = %s", bundleInfos[i].versionCode, bundleInfos[i].versionName); static_print_debug("RversionCode = %s RversionName = %s", unitInfoList[i].versionCode, unitInfoList[i].versionName); } char *jsonStr = ConvertToCjson(unitInfoList); static_print_debug("json = %s", jsonStr); if (jsonStr) { int saveResult = SaveJsonToFile(jsonStr); if (saveResult != 0) { ret = false; static_print_error("Save failed with code %d", saveResult); } free(jsonStr); } else { ret = false; } if (bundleInfos != nullptr) { for (uint8_t i = 0; i < count; i++) { ClearBundleInfo(bundleInfos + i); } AdapterFree(bundleInfos); } return ret; } void RegisterPkgOperationCallback(pkgOperationCallback callback) { g_pkgOperationCallbackList.emplace_back(callback); } void UnRegisterPkgOperationCallback(pkgOperationCallback callback) { g_pkgOperationCallbackList.remove(callback); }