289 lines
10 KiB
C++
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); } |