mcu_hi3321_watch/tjd/ui/common/TjdAppStore.cpp
2025-05-26 20:15:20 +08:00

289 lines
10 KiB
C++

/*----------------------------------------------------------------------------
* 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 <list>
#include <unistd.h>
#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<pkgOperationCallback> 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<PkgUnitInfo> &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<const char *>(pkgInfo.pkgName);
const char *label = reinterpret_cast<const char *>(pkgInfo.label);
const char *versionName = reinterpret_cast<const char *>(pkgInfo.versionName);
const char *versionCode = reinterpret_cast<const char *>(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<PkgUnitInfo> 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); }