• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "enable_upgrade_manager.h"
16 
17 #include "file_operator.h"
18 #include "ime_info_inquirer.h"
19 #include "os_account_adapter.h"
20 #include "parameter.h"
21 #include "settings_data_utils.h"
22 namespace OHOS {
23 namespace MiscServices {
24 constexpr const char *IME_CFG_FILE_PATH = "/data/service/el1/public/imf/ime_cfg.json";
GetInstance()25 EnableUpgradeManager &EnableUpgradeManager::GetInstance()
26 {
27     static EnableUpgradeManager instance;
28     return instance;
29 }
30 
Upgrade(int32_t userId,const std::vector<FullImeInfo> & imeInfos)31 int32_t EnableUpgradeManager::Upgrade(int32_t userId, const std::vector<FullImeInfo> &imeInfos)
32 {
33     std::lock_guard<std::mutex> lock(upgradedLock_);
34     if (upgradedUserId_.count(userId)) {
35         return ErrorCode::NO_ERROR;
36     }
37     std::string userContent;
38     auto ret = GetUserEnabledTable(userId, userContent);
39     if (ret != ErrorCode::NO_ERROR && ret != ErrorCode::ERROR_KEYWORD_NOT_FOUND) {
40         return ret;
41     }
42     bool needUpgrade = userContent.find("version") == std::string::npos;
43     if (!needUpgrade) {
44         upgradedUserId_.insert(userId);
45         return ErrorCode::NO_ERROR;
46     }
47     ImeEnabledCfg cfg;
48     cfg.version = GetDisplayVersion();
49     ret = MergeTwoTable(userId, cfg.enabledInfos);
50     if (ret != ErrorCode::NO_ERROR) {
51         return ret;
52     }
53     ret = PaddedByBundleMgr(userId, imeInfos, cfg.enabledInfos);
54     if (ret != ErrorCode::NO_ERROR) {
55         return ret;
56     }
57     ret = PaddedByImePersistCfg(userId, cfg.enabledInfos);
58     if (ret != ErrorCode::NO_ERROR) {
59         return ret;
60     }
61     std::string newContent;
62     cfg.Marshall(newContent);
63     if (!SetUserEnabledTable(userId, newContent)) {
64         IMSA_HILOGE("%{public}d set enabled table failed.", userId);
65         return ErrorCode::ERROR_ENABLE_IME;
66     }
67     upgradedUserId_.insert(userId);
68     return ErrorCode::NO_ERROR;
69 }
70 
GetEnabledTable(int32_t userId,std::set<std::string> & bundleNames)71 int32_t EnableUpgradeManager::GetEnabledTable(int32_t userId, std::set<std::string> &bundleNames)
72 {
73     auto ret = GetGlobalEnabledTable(userId, bundleNames);
74     if (ret == ErrorCode::ERROR_EX_PARCELABLE) {
75         return GetUserEnabledTable(userId, bundleNames);
76     }
77     return ret;
78 }
79 
GetGlobalEnabledTable(int32_t userId,std::string & content)80 int32_t EnableUpgradeManager::GetGlobalEnabledTable(int32_t userId, std::string &content)
81 {
82     return GetEnabledTable(userId, SETTING_URI_PROXY, content);
83 }
84 
GetUserEnabledTable(int32_t userId,std::string & content)85 int32_t EnableUpgradeManager::GetUserEnabledTable(int32_t userId, std::string &content)
86 {
87     std::string uriProxy = SETTINGS_USER_DATA_URI + std::to_string(userId) + "?Proxy=true";
88     return GetEnabledTable(userId, uriProxy, content);
89 }
90 
GetGlobalEnabledTable(int32_t userId,std::set<std::string> & bundleNames)91 int32_t EnableUpgradeManager::GetGlobalEnabledTable(int32_t userId, std::set<std::string> &bundleNames)
92 {
93     return GetEnabledTable(userId, SETTING_URI_PROXY, bundleNames);
94 }
95 
GetUserEnabledTable(int32_t userId,std::set<std::string> & bundleNames)96 int32_t EnableUpgradeManager::GetUserEnabledTable(int32_t userId, std::set<std::string> &bundleNames)
97 {
98     std::string uriProxy = SETTINGS_USER_DATA_URI + std::to_string(userId) + "?Proxy=true";
99     return GetEnabledTable(userId, uriProxy, bundleNames);
100 }
101 
GetEnabledTable(int32_t userId,const std::string & uriProxy,std::set<std::string> & bundleNames)102 int32_t EnableUpgradeManager::GetEnabledTable(
103     int32_t userId, const std::string &uriProxy, std::set<std::string> &bundleNames)
104 {
105     std::string content;
106     auto ret = GetEnabledTable(userId, uriProxy, content);
107     if (ret != ErrorCode::NO_ERROR) {
108         return ret;
109     }
110     return ParseEnabledTable(userId, content, bundleNames);
111 }
112 
GetEnabledTable(int32_t userId,const std::string & uriProxy,std::string & content)113 int32_t EnableUpgradeManager::GetEnabledTable(int32_t userId, const std::string &uriProxy, std::string &content)
114 {
115     return SettingsDataUtils::GetInstance().GetStringValue(uriProxy, SettingsDataUtils::ENABLE_IME, content);
116 }
117 
ParseEnabledTable(int32_t userId,std::string & content,std::set<std::string> & bundleNames)118 int32_t EnableUpgradeManager::ParseEnabledTable(
119     int32_t userId, std::string &content, std::set<std::string> &bundleNames)
120 {
121     EnabledImeCfg oldCfg;
122     oldCfg.userImeCfg.userId = std::to_string(userId);
123     if (!oldCfg.Unmarshall(content)) {
124         IMSA_HILOGE("%{public}d Unmarshall failed:%{public}s.", userId, content.c_str());
125         return ErrorCode::ERROR_EX_PARCELABLE;
126     }
127     bundleNames = std::set<std::string>(oldCfg.userImeCfg.identities.begin(), oldCfg.userImeCfg.identities.end());
128     return ErrorCode::NO_ERROR;
129 }
130 
GetFullExperienceTable(int32_t userId,std::set<std::string> & bundleNames)131 int32_t EnableUpgradeManager::GetFullExperienceTable(int32_t userId, std::set<std::string> &bundleNames)
132 {
133     std::string content;
134     int32_t ret = SettingsDataUtils::GetInstance().GetStringValue(SETTING_URI_PROXY,
135         SettingsDataUtils::SECURITY_MODE, content);
136     if (ret != ErrorCode::NO_ERROR) {
137         IMSA_HILOGW("%{public}d get full experience table failed:%{public}d.", userId, ret);
138         return ret;
139     }
140     SecurityModeCfg cfg;
141     cfg.userImeCfg.userId = std::to_string(userId);
142     if (!cfg.Unmarshall(content)) {
143         IMSA_HILOGE("%{public}d Unmarshall failed:%{public}s.", userId, content.c_str());
144         return ErrorCode::ERROR_EX_PARCELABLE;
145     }
146     bundleNames = std::set<std::string>(cfg.userImeCfg.identities.begin(), cfg.userImeCfg.identities.end());
147     return ErrorCode::NO_ERROR;
148 }
149 
MergeTwoTable(int32_t userId,std::vector<ImeEnabledInfo> & enabledInfos)150 int32_t EnableUpgradeManager::MergeTwoTable(int32_t userId, std::vector<ImeEnabledInfo> &enabledInfos)
151 {
152     std::set<std::string> enabledBundleNames;
153     auto ret = GetEnabledTable(userId, enabledBundleNames);
154     if (ret != ErrorCode::NO_ERROR && ret != ErrorCode::ERROR_KEYWORD_NOT_FOUND &&
155         ret != ErrorCode::ERROR_EX_PARCELABLE) {
156         IMSA_HILOGE("%{public}d get enabled table failed:%{public}d.", userId, ret);
157         return ret;
158     }
159     std::set<std::string> fullModeBundleNames;
160     ret = GetFullExperienceTable(userId, fullModeBundleNames);
161     if (ret != ErrorCode::NO_ERROR && ret != ErrorCode::ERROR_KEYWORD_NOT_FOUND &&
162         ret != ErrorCode::ERROR_EX_PARCELABLE) {
163         IMSA_HILOGE("%{public}d get full experience table failed:%{public}d.", userId, ret);
164         return ret;
165     }
166     for (const auto &bundleName : enabledBundleNames) {
167         ImeEnabledInfo tmpInfo;
168         tmpInfo.bundleName = bundleName;
169         tmpInfo.enabledStatus = EnabledStatus::BASIC_MODE;
170         enabledInfos.push_back(tmpInfo);
171     }
172     for (const auto &bundleName : fullModeBundleNames) {
173         auto iter = std::find_if(enabledInfos.begin(), enabledInfos.end(),
174             [&bundleName](const ImeEnabledInfo &info) { return info.bundleName == bundleName; });
175         if (iter != enabledInfos.end()) {
176             iter->enabledStatus = EnabledStatus::FULL_EXPERIENCE_MODE;
177             continue;
178         }
179         ImeEnabledInfo tmpInfo;
180         tmpInfo.bundleName = bundleName;
181         tmpInfo.enabledStatus = EnabledStatus::FULL_EXPERIENCE_MODE;
182         enabledInfos.push_back(tmpInfo);
183     }
184     return ErrorCode::NO_ERROR;
185 }
186 
PaddedByBundleMgr(int32_t userId,const std::vector<FullImeInfo> & imeInfos,std::vector<ImeEnabledInfo> & enabledInfos)187 int32_t EnableUpgradeManager::PaddedByBundleMgr(
188     int32_t userId, const std::vector<FullImeInfo> &imeInfos, std::vector<ImeEnabledInfo> &enabledInfos)
189 {
190     auto finalImeInfos = imeInfos;
191     if (finalImeInfos.empty()) {
192         auto ret = ImeInfoInquirer::GetInstance().QueryFullImeInfo(userId, finalImeInfos, true);
193         if (ret != ErrorCode::NO_ERROR) {
194             IMSA_HILOGE("%{public}d QueryFullImeInfo failed:%{public}d.", userId, ret);
195             return ret;
196         }
197     }
198     IMSA_HILOGI("ime size, enabled:%{public}zu, installed:%{public}zu.", enabledInfos.size(), finalImeInfos.size());
199     for (const auto &info : finalImeInfos) {
200         auto iter = std::find_if(enabledInfos.begin(), enabledInfos.end(),
201             [&info](const ImeEnabledInfo &enabledInfoTmp) { return enabledInfoTmp.bundleName == info.prop.name; });
202         if (iter != enabledInfos.end()) {
203             IMSA_HILOGI("%{public}d/%{public}s:%{public}d before upgrade.", userId, info.prop.name.c_str(),
204                 static_cast<int32_t>(iter->enabledStatus));
205             iter->extensionName = info.prop.id;
206             continue;
207         }
208         IMSA_HILOGI("%{public}d/%{public}s is disabled before upgrade or sys ime.", userId, info.prop.name.c_str());
209         enabledInfos.emplace_back(
210             info.prop.name, info.prop.id, ComputeEnabledStatus(info.prop.name, EnabledStatus::DISABLED));
211     }
212     return ErrorCode::NO_ERROR;
213 }
214 // LCOV_EXCL_START
UpdateGlobalEnabledTable(int32_t userId,const ImeEnabledCfg & newEnabledCfg)215 void EnableUpgradeManager::UpdateGlobalEnabledTable(int32_t userId, const ImeEnabledCfg &newEnabledCfg)
216 {
217     if (!ImeInfoInquirer::GetInstance().GetSystemConfig().enableInputMethodFeature) {
218         return;
219     }
220     auto currentUserId = OsAccountAdapter::GetForegroundOsAccountLocalId();
221     if (userId != currentUserId) {
222         IMSA_HILOGW("[%{public}d,%{public}d] not same.", userId, currentUserId);
223         return;
224     }
225     std::vector<std::string> newBundleNames;
226     for (const auto &info : newEnabledCfg.enabledInfos) {
227         if (info.enabledStatus != EnabledStatus::DISABLED &&
228             ImeInfoInquirer::GetInstance().IsImeInstalled(userId, info.bundleName, info.extensionName)) {
229             newBundleNames.emplace_back(info.bundleName);
230         }
231     }
232     std::string oldGlobalContent;
233     auto ret = GetGlobalEnabledTable(userId, oldGlobalContent);
234     if (ret != ErrorCode::NO_ERROR && ret != ErrorCode::ERROR_KEYWORD_NOT_FOUND) {
235         IMSA_HILOGW("%{public}d get global enabled table failed:%{public}d.", userId, ret);
236         return;
237     }
238     IMSA_HILOGD("old global content:%{public}s.", oldGlobalContent.c_str());
239     auto newGlobalContent = GenerateGlobalContent(userId, newBundleNames);
240     if (newGlobalContent.empty()) {
241         IMSA_HILOGE("newGlobalContent is empty.");
242         return;
243     }
244     if (newGlobalContent == oldGlobalContent) {
245         IMSA_HILOGD("content same, not deal.");
246         return;
247     }
248     IMSA_HILOGD("global content, old:%{public}s, new:%{public}s.", oldGlobalContent.c_str(), newGlobalContent.c_str());
249     auto globalTableUserId = GetGlobalTableUserId(oldGlobalContent);
250     if (globalTableUserId == -1 || userId == globalTableUserId) {
251         SetGlobalEnabledTable(newGlobalContent);
252         return;
253     }
254     ret = Upgrade(globalTableUserId, {});
255     if (ret != ErrorCode::NO_ERROR) {
256         IMSA_HILOGW("%{public}d Upgrade failed:%{public}d.", userId, ret);
257         return;
258     }
259     SetGlobalEnabledTable(newGlobalContent);
260 }
261 // LCOV_EXCL_STOP
GetGlobalTableUserId(const std::string & valueStr)262 int32_t EnableUpgradeManager::GetGlobalTableUserId(const std::string &valueStr)
263 {
264     auto root = cJSON_Parse(valueStr.c_str());
265     if (root == nullptr) {
266         IMSA_HILOGE("valueStr content parse failed!");
267         return -1;
268     }
269     auto subNode = Serializable::GetSubNode(root, "enableImeList");
270     if (subNode == nullptr || !cJSON_IsObject(subNode)) {
271         IMSA_HILOGW("subNode is null or not object");
272         cJSON_Delete(root);
273         return -1;
274     }
275     if (subNode->child == nullptr) {
276         IMSA_HILOGW("subNode has not child");
277         cJSON_Delete(root);
278         return -1;
279     }
280     std::string userId = subNode->child->string;
281     cJSON_Delete(root);
282     return atoi(userId.c_str());
283 }
284 
GenerateGlobalContent(int32_t userId,const std::vector<std::string> & bundleNames)285 std::string EnableUpgradeManager::GenerateGlobalContent(int32_t userId, const std::vector<std::string> &bundleNames)
286 {
287     EnabledImeCfg cfg;
288     cfg.userImeCfg.identities = bundleNames;
289     std::string newGlobalContent;
290     cfg.userImeCfg.userId = std::to_string(userId);
291     if (!cfg.Marshall(newGlobalContent)) {
292         IMSA_HILOGE("%{public}d Marshall failed.", userId);
293     }
294     return newGlobalContent;
295 }
296 // LCOV_EXCL_START
SetGlobalEnabledTable(const std::string & content)297 bool EnableUpgradeManager::SetGlobalEnabledTable(const std::string &content)
298 {
299     return SetEnabledTable(SETTING_URI_PROXY, content);
300 }
301 
SetUserEnabledTable(int32_t userId,const std::string & content)302 bool EnableUpgradeManager::SetUserEnabledTable(int32_t userId, const std::string &content)
303 {
304     std::string uriProxy = SETTINGS_USER_DATA_URI + std::to_string(userId) + "?Proxy=true";
305     return SetEnabledTable(uriProxy, content);
306 }
307 
SetEnabledTable(const std::string & uriProxy,const std::string & content)308 bool EnableUpgradeManager::SetEnabledTable(const std::string &uriProxy, const std::string &content)
309 {
310     return SettingsDataUtils::GetInstance().SetStringValue(uriProxy, SettingsDataUtils::ENABLE_IME, content);
311 }
312 // LCOV_EXCL_STOP
GetImePersistCfg(int32_t userId,ImePersistInfo & persisInfo)313 int32_t EnableUpgradeManager::GetImePersistCfg(int32_t userId, ImePersistInfo &persisInfo)
314 {
315     if (!FileOperator::IsExist(IME_CFG_FILE_PATH)) {
316         IMSA_HILOGD("ime cfg file not found.");
317         return ErrorCode::NO_ERROR;
318     }
319     std::string content;
320     if (!FileOperator::Read(IME_CFG_FILE_PATH, content)) {
321         IMSA_HILOGE("failed to read persist info!");
322         return ErrorCode::ERROR_PERSIST_CONFIG;
323     }
324     IMSA_HILOGI("content: %{public}s", content.c_str());
325     ImePersistCfg cfg;
326     if (!cfg.Unmarshall(content)) {
327         IMSA_HILOGE("Unmarshall failed!");
328         return ErrorCode::NO_ERROR;
329     }
330     auto iter = std::find_if(cfg.imePersistInfo.begin(), cfg.imePersistInfo.end(),
331         [userId](const auto &infoTmp) { return infoTmp.userId == userId; });
332     if (iter != cfg.imePersistInfo.end()) {
333         persisInfo = *iter;
334     }
335     return ErrorCode::NO_ERROR;
336 }
337 
PaddedByImePersistCfg(int32_t userId,std::vector<ImeEnabledInfo> & enabledInfos)338 int32_t EnableUpgradeManager::PaddedByImePersistCfg(int32_t userId, std::vector<ImeEnabledInfo> &enabledInfos)
339 {
340     ImePersistInfo persistInfo;
341     auto ret = GetImePersistCfg(userId, persistInfo);
342     if (ret != ErrorCode::NO_ERROR) {
343         return ret;
344     }
345     std::string currentBundleName;
346     std::string currentExtName;
347     auto pos = persistInfo.currentIme.find('/');
348     if (pos != std::string::npos && pos + 1 < persistInfo.currentIme.size()) {
349         currentBundleName = persistInfo.currentIme.substr(0, pos);
350         currentExtName = persistInfo.currentIme.substr(pos + 1);
351     }
352     auto iter = std::find_if(
353         enabledInfos.begin(), enabledInfos.end(), [&currentBundleName, &currentExtName](const auto &infoTmp) {
354             return infoTmp.bundleName == currentBundleName && infoTmp.extensionName == currentExtName &&
355                    infoTmp.enabledStatus != EnabledStatus::DISABLED;
356         });
357     if (iter != enabledInfos.end()) {
358         iter->extraInfo.isDefaultIme = true;
359         iter->extraInfo.isDefaultImeSet = persistInfo.isDefaultImeSet;
360         iter->extraInfo.currentSubName = persistInfo.currentSubName;
361     } else {
362         auto sysIter = std::find_if(enabledInfos.begin(), enabledInfos.end(), [](const ImeEnabledInfo &enabledInfoTmp) {
363             return enabledInfoTmp.bundleName == ImeInfoInquirer::GetInstance().GetDefaultIme().bundleName;
364         });
365         if (sysIter != enabledInfos.end()) {
366             sysIter->extraInfo.isDefaultIme = true;
367         }
368     }
369 
370     std::string tmpBundleName;
371     std::string tmpExtName;
372     pos = persistInfo.tempScreenLockIme.find('/');
373     if (pos != std::string::npos && pos + 1 < persistInfo.tempScreenLockIme.size()) {
374         tmpBundleName = persistInfo.tempScreenLockIme.substr(0, pos);
375         tmpExtName = persistInfo.tempScreenLockIme.substr(pos + 1);
376     }
377     iter = std::find_if(enabledInfos.begin(), enabledInfos.end(), [&tmpBundleName, &tmpExtName](const auto &infoTmp) {
378         return infoTmp.bundleName == tmpBundleName && infoTmp.extensionName == tmpExtName;
379     });
380     if (iter != enabledInfos.end()) {
381         iter->extraInfo.isTmpIme = true;
382     }
383     return ErrorCode::NO_ERROR;
384 }
385 
ComputeEnabledStatus(const std::string & bundleName,EnabledStatus initStatus)386 EnabledStatus EnableUpgradeManager::ComputeEnabledStatus(const std::string &bundleName, EnabledStatus initStatus)
387 {
388     auto sysCfg = ImeInfoInquirer::GetInstance().GetSystemConfig();
389     auto hasEnableSwitch = sysCfg.enableInputMethodFeature;
390     auto hasFullExperienceSwitch = sysCfg.enableFullExperienceFeature;
391     IMSA_HILOGI("enable cfg:[%{public}d, %{public}d].", hasEnableSwitch, hasFullExperienceSwitch);
392     if (!hasEnableSwitch && !hasFullExperienceSwitch) {
393         return EnabledStatus::FULL_EXPERIENCE_MODE;
394     }
395     auto sysIme = ImeInfoInquirer::GetInstance().GetDefaultIme();
396     if (bundleName == sysIme.bundleName && initStatus == EnabledStatus::DISABLED) {
397         return EnabledStatus::BASIC_MODE;
398     }
399     return initStatus;
400 }
401 } // namespace MiscServices
402 } // namespace OHOS