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(), [¤tBundleName, ¤tExtName](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