1 /*
2  * Copyright (c) 2021-2023 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 
16 #ifndef FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MGR_SERVICE_EVENT_HANDLER_H
17 #define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MGR_SERVICE_EVENT_HANDLER_H
18 
19 #include <list>
20 #include <unordered_set>
21 
22 #include "bundle_constants.h"
23 #include "bundle_data_mgr.h"
24 #include "bundle_mgr_host_impl.h"
25 #include "pre_scan_info.h"
26 #include "nlohmann/json.hpp"
27 
28 namespace OHOS {
29 namespace AppExecFwk {
30 class BundleMgrService;
31 enum class ScanMode;
32 enum class ResultMode;
33 
34 enum class ResultCode {
35     RECOVER_OK = 0,
36     REINSTALL_OK,
37     NO_INSTALLED_DATA,
38     SYSTEM_ERROR,
39 };
40 
41 enum OTAFlag {
42     CHECK_ELDIR = 0x00000001,
43     CHECK_LOG_DIR = 0x00000010,
44     CHECK_FILE_MANAGER_DIR = 0x00000100,
45     CHECK_SHADER_CAHCE_DIR = 0x00000200,
46     CHECK_PREINSTALL_DATA = 0x00000400,
47     CHECK_CLOUD_SHADER_DIR = 0x00000800,
48     CHECK_BACK_UP_DIR = 0x00001000,
49     CHECK_RECOVERABLE_APPLICATION_INFO = 0x00002000,
50 };
51 
52 enum class ScanResultCode {
53     SCAN_HAS_DATA_PARSE_SUCCESS,
54     SCAN_HAS_DATA_PARSE_FAILED,
55     SCAN_NO_DATA,
56 };
57 
58 class BMSEventHandler {
59 public:
60     BMSEventHandler();
61     ~BMSEventHandler();
62     /**
63      * @brief Get preInstall root dir list,
64      *        which the catalog of production has higher priority.
65      * @param rootDirList Indicates the root dir list.
66      * @return
67      */
68     static void GetPreInstallRootDirList(std::vector<std::string> &rootDirList);
69     /**
70      * @brief Load all preInstall infos from proFile.
71      * @return Returns true if get the preInstall list successfully; returns false otherwise.
72      */
73     static bool LoadPreInstallProFile();
74     /**
75      * @brief Clear all preInstall infos cache.
76      * @return
77      */
78     static void ClearPreInstallCache();
79     /**
80      * @brief Get the preInstall capability.
81      * @param preBundleConfigInfo Indicates the preBundleConfigInfo.
82      * @return Returns true if get the preInstall capability successfully; returns false otherwise.
83      */
84     static bool GetPreInstallCapability(PreBundleConfigInfo &preBundleConfigInfo);
85     /**
86      * @brief Check extension type name in the configuration file.
87      * @param extensionTypeName Indicates the extensionTypeName to check in the configuration file.
88      * @return Returns true if the extensionTypeName is in the configuration file; returns false otherwise.
89      */
90     static bool CheckExtensionTypeInConfig(const std::string &extensionTypeName);
91     /**
92      * @brief Has preInstall profile or not.
93      * @return Returns result.
94      */
95     static bool HasPreInstallProfile();
96     /**
97      * @brief Bms start event.
98      * @return
99      */
100     void BmsStartEvent();
101 
102     static void ProcessRebootQuickFixBundleInstall(const std::string &path, bool isOta);
103 
104     static void ProcessRebootQuickFixUnInstallAndRecover(const std::string &path);
105 
106     static void SavePreInstallException(const std::string &bundleDir);
107 
108     static void ProcessSystemBundleInstall(
109         const PreScanInfo &preScanInfo,
110         Constants::AppType appType,
111         int32_t userId = Constants::UNSPECIFIED_USERID);
112 
113 private:
114     /**
115      * @brief Before Bms start.
116      * @return
117      */
118     void BeforeBmsStart();
119     /**
120      * @brief On Bms starting.
121      * @return
122      */
123     void OnBmsStarting();
124     /**
125      * @brief After Bms start.
126      * @return
127      */
128     void AfterBmsStart();
129     /**
130      * @brief Load install infos from db.
131      * @return Returns true if load successfully; returns false otherwise.
132      */
133     bool LoadInstallInfosFromDb();
134     /**
135      * @brief Guard against install infos lossed strategy.
136      * @return Returns ResultCode for recover install infos.
137      */
138     ResultCode GuardAgainstInstallInfosLossedStrategy();
139     /**
140      * @brief Scan and analyze install infos.
141      * @param installInfos Indicates the install infos.
142      * @return
143      */
144     void ScanAndAnalyzeInstallInfos(
145         std::map<std::string, std::vector<InnerBundleInfo>> &installInfos);
146     /**
147      * @brief Scan and analyze common install dir.
148      * @param installInfos Indicates the install infos.
149      * @return
150      */
151     void ScanInstallDir(
152         std::map<std::string, std::vector<std::string>> &hapPathsMap);
153     /**
154      * @brief Get preInstall haps.
155      * @param bundleDirs Indicates preInstall hapPath.
156      * @return
157      */
158     void GetPreInstallDir(std::vector<std::string> &bundleDirs);
159     /**
160      * @brief Analyze hap to InnerBundleInfo.
161      * @param isPreInstallApp Indicates is preInstallApp or not.
162      * @param hapPathsMap Indicates the hapPathsMap which will be analyzed.
163      * @param installInfos Indicates the install infos.
164      * @return
165      */
166     void AnalyzeHaps(
167         bool isPreInstallApp,
168         const std::map<std::string, std::vector<std::string>> &hapPathsMap,
169         std::map<std::string, std::vector<InnerBundleInfo>> &installInfos);
170     /**
171      * @brief Analyze hap to InnerBundleInfo.
172      * @param isPreInstallApp Indicates is preInstallApp or not.
173      * @param bundleDirs Indicates the bundleDirs which will be analyzed.
174      * @param installInfos Indicates the install infos.
175      * @return
176      */
177     void AnalyzeHaps(
178         bool isPreInstallApp,
179         const std::vector<std::string> &bundleDirs,
180         std::map<std::string, std::vector<InnerBundleInfo>> &installInfos);
181     /**
182      * @brief Get preBundle install dir.
183      * @param bundleDirs Indicates the bundleDirs.
184      * @return
185      */
186     void GetPreBundleDir(std::list<std::string> &bundleDirs);
187     /**
188      * @brief Check scaned hapPath whether end with .hap.
189      * @param hapPaths Indicates the hapPaths.
190      * @return Returns the checked hapPaths.
191      */
192     std::vector<std::string> CheckHapPaths(const std::vector<std::string> &hapPaths);
193     /**
194      * @brief Collect install infos from parse result.
195      * @param hapInfos Indicates the parse result.
196      * @param installInfos Indicates the saved installInfos.
197      * @return.
198      */
199     void CollectInstallInfos(
200         const std::unordered_map<std::string, InnerBundleInfo> &hapInfos,
201         std::map<std::string, std::vector<InnerBundleInfo>> &installInfos);
202     /**
203      * @brief Scan and analyze userDatas.
204      * @param userMaps Indicates the userMaps to save userInfo.
205      * @return Returns ScanResultCode if Scan and analyze infos successfully; returns false otherwise.
206      */
207     ScanResultCode ScanAndAnalyzeUserDatas(
208         std::map<std::string, std::vector<InnerBundleUserInfo>> &userMaps);
209     /**
210      * @brief Analyze userDatas.
211      * @param userId Indicates the userId.
212      * @param userDataDir Indicates the userDataDir.
213      * @param userDataBundleName Indicates the userDataBundleName.
214      * @param userMaps Indicates the userMaps to save userInfo.
215      * @return Returns true if analyze infos successfully; returns false otherwise.
216      */
217     bool AnalyzeUserData(
218         int32_t userId, const std::string &userDataDir, const std::string &userDataBundleName,
219         std::map<std::string, std::vector<InnerBundleUserInfo>> &userMaps);
220     /**
221      * @brief ReInstall all Apps from installDir.
222      * @return Returns the ResultCode indicates the result of this action.
223      */
224     ResultCode ReInstallAllInstallDirApps();
225     /**
226      * @brief Combine install infos and userInfos.
227      * @param installInfos Indicates the installInfos.
228      * @param userInfoMaps Indicates the userInfoMaps.
229      * @return Returns true if combine infos successfully; returns false otherwise.
230      */
231     bool CombineBundleInfoAndUserInfo(
232         const std::map<std::string, std::vector<InnerBundleInfo>> &installInfos,
233         const std::map<std::string, std::vector<InnerBundleUserInfo>> &userInfoMaps);
234     /**
235      * @brief Save recover info to cache.
236      * @param info Indicates the InnerBundleInfo.
237      * @return
238      */
239     void SaveInstallInfoToCache(InnerBundleInfo &info);
240     /**
241      * @brief Scan dir by scanMode and resultMode, this function will perform
242      *        scan through installd because installd has higher permissions.
243      * @param scanMode Indicates the scanMode,
244      *        which maybe SUB_FILE_ALL SUB_FILE_DIR or SUB_FILE_FILE.
245      * @param resultMode Indicates the resultMode,
246      *        which maybe ABSOLUTE_PATH or RELATIVE_PATH.
247      * @param resultList Indicates the scan resultList.
248      * @return Returns true if Scan successfully; returns false otherwise.
249      */
250     bool ScanDir(const std::string& dir, ScanMode scanMode,
251         ResultMode resultMode, std::vector<std::string> &resultList);
252     /**
253      * @brief Bundle boot start event.
254      * @return
255      */
256     void BundleBootStartEvent();
257     /**
258      * @brief Bundle reboot start event.
259      * @return
260      */
261     void BundleRebootStartEvent();
262     /**
263      * @brief start boot scan.
264      * @param userId Indicates the userId.
265      * @return
266      */
267     void OnBundleBootStart(int32_t userId = Constants::UNSPECIFIED_USERID);
268     /**
269      * @brief Process boot bundle install from scan.
270      * @param userId Indicates the userId.
271      * @return
272      */
273     void ProcessBootBundleInstallFromScan(int32_t userId);
274     /**
275      * @brief Process bundle install by scanInfos.
276      * @param userId Indicates the userId.
277      * @return
278      */
279     void InnerProcessBootPreBundleProFileInstall(int32_t userId);
280     /**
281      * @brief Install bundles by scanDir.
282      * @param scanDir Indicates the scanDir.
283      * @param appType Indicates the bundle type.
284      * @param userId Indicates userId.
285      * @return
286      */
287     void ProcessSystemBundleInstall(
288         const std::string &scanDir,
289         Constants::AppType appType,
290         int32_t userId = Constants::UNSPECIFIED_USERID);
291     /**
292      * @brief Install system shared bundle.
293      * @param sharedBundlePath Indicates the path of shared bundle.
294      * @param appType Indicates the bundle type.
295      * @return
296      */
297     void ProcessSystemSharedBundleInstall(const std::string &sharedBundlePath, Constants::AppType appType);
298     /**
299      * @brief start reboot scan.
300      * @return
301      */
302     void OnBundleRebootStart();
303     /**
304      * @brief Process reboot bundle.
305      * @return
306      */
307     void ProcessRebootBundle();
308     /**
309      * @brief Obtains the PreInstallBundleInfo objects.
310      * @return Returns true if this function is successfully called; returns false otherwise.
311      */
312     bool LoadAllPreInstallBundleInfos();
313     /**
314      * @brief Process reboot bundle install.
315      * @return
316      */
317     void ProcessRebootBundleInstall();
318     /**
319      * @brief Process reboot bundle install by scanInfos.
320      * @return
321      */
322     void ProcessReBootPreBundleProFileInstall();
323     /**
324      * @brief Process reboot bundle install from scan.
325      * @return
326      */
327     void ProcessRebootBundleInstallFromScan();
328     /**
329      * @brief Process reboot install bundles by bundleList.
330      * @param bundleList Indicates store bundle list.
331      * @param appType Indicates the bundle type.
332      * @return
333      */
334     void InnerProcessRebootBundleInstall(
335         const std::list<std::string> &bundleList, Constants::AppType appType);
336     /**
337      * @brief Process reboot install shared bundles by bundleList.
338      * @param bundleList Indicates store bundle list.
339      * @param appType Indicates the bundle type.
340      * @return
341      */
342     void InnerProcessRebootSharedBundleInstall(const std::list<std::string> &bundleList, Constants::AppType appType);
343     /**
344      * @brief Process reboot install system hsp by bundleList.
345      * @param scanPathList Indicates store bundle list.
346      * @return
347      */
348     void InnerProcessRebootSystemHspInstall(const std::list<std::string> &scanPathList);
349     /**
350      * @brief Reboot uninstall system and system vendor bundles.
351      * @return
352      */
353     void ProcessRebootBundleUninstall();
354     /**
355      * @brief Get bundle dir by scan.
356      * @param bundleDirs Indicates the return bundleDirs.
357      * @return
358      */
359     void GetBundleDirFromScan(std::list<std::string> &bundleDirs);
360     /**
361      * @brief Process scan dir.
362      * @param dir Indicates the dir.
363      * @param bundleDirs Indicates the return bundleDirs.
364      * @return
365      */
366     static void ProcessScanDir(const std::string &dir, std::list<std::string> &bundleDirs);
367     /**
368      * @brief Process parse pre bundle profile.
369      * @param dir Indicates the dir.
370      * @return
371      */
372     static void ParsePreBundleProFile(const std::string &dir);
373     /**
374      * @brief Set the flag indicates that all system and vendor applications installed.
375      * @return
376      */
377     void CreateAppInstallDir() const;
378     void SetAllInstallFlag() const;
379     /**
380      * @brief Check and parse hap.
381      * @param hapFilePath Indicates the absolute file path of the HAP.
382      * @param isPreInstallApp Indicates the hap is preInstallApp or not.
383      * @param infos Indicates the obtained BundleInfo object.
384      * @return Returns true if the BundleInfo is successfully obtained; returns false otherwise.
385      */
386     bool CheckAndParseHapFiles(const std::string &hapFilePath,
387         bool isPreInstallApp, std::unordered_map<std::string, InnerBundleInfo> &infos);
388     /**
389      * @brief Parse hap.
390      * @param hapFilePath Indicates the absolute file path of the HAP.
391      * @param infos Indicates the obtained BundleInfo object.
392      * @return Returns true if the BundleInfo is successfully obtained; returns false otherwise.
393      */
394     static bool ParseHapFiles(
395         const std::string &hapFilePath,
396         std::unordered_map<std::string, InnerBundleInfo> &infos);
397     /**
398      * @brief OTA Install system app and system vendor bundles.
399      * @param filePaths Indicates the filePaths.
400      * @param appType Indicates the bundle type.
401      * @param removable Indicates whether it can be removed.
402      * @return Returns true if this function called successfully; returns false otherwise.
403      */
404     bool OTAInstallSystemBundle(
405         const std::vector<std::string> &filePaths,
406         Constants::AppType appType,
407         bool removable);
408 
409     /**
410      * @brief OTA Install system app and system vendor bundles.
411      * @param filePaths Indicates the filePaths.
412      * @param bundleName Indicates the bundleName.
413      * @param appType Indicates the bundle type.
414      * @param removable Indicates whether it can be removed.
415      * @return Returns true if this function called successfully; returns false otherwise.
416      */
417     static bool OTAInstallSystemBundleNeedCheckUser(
418         const std::vector<std::string> &filePaths,
419         const std::string &bundleName,
420         Constants::AppType appType,
421         bool removable);
422     /**
423      * @brief OTA Install system app and system vendor shared bundles.
424      * @param filePaths Indicates the filePaths.
425      * @param appType Indicates the bundle type.
426      * @param removable Indicates whether it can be removed.
427      * @return Returns true if this function called successfully; returns false otherwise.
428      */
429     bool OTAInstallSystemSharedBundle(
430         const std::vector<std::string> &filePaths,
431         Constants::AppType appType,
432         bool removable);
433     /**
434      * @brief OTA Install system hsp.
435      * @param filePaths Indicates the filePaths.
436      * @return Returns ERR_OK if this function called successfully; returns false otherwise.
437      */
438     ErrCode OTAInstallSystemHsp(const std::vector<std::string> &filePaths);
439     /**
440      * @brief version is the same, determine whether to update based on the buildHash
441      * @param oldInfo Indicates the old innerBundleInfo.
442      * @param newInfo Indicates the new innerBundleInfo.
443      * @return Returns true if need to update.
444      */
445     bool IsNeedToUpdateSharedHspByHash(const InnerBundleInfo &oldInfo, const InnerBundleInfo &newInfo) const;
446     /**
447      * @brief Used to determine whether the module has been installed. If the installation has
448      *        been uninstalled, OTA install and upgrade will not be allowed.
449      * @param bundleName Indicates the bundleName.
450      * @param bundlePath Indicates the bundlePath.
451      * @return Returns true if this function called successfully; returns false otherwise.
452      */
453     bool HasModuleSavedInPreInstalledDb(
454         const std::string &bundleName, const std::string &bundlePath);
455     /**
456      * @brief Delete preInstallInfo to Db.
457      * @param bundleName Indicates the bundleName.
458      * @param bundlePath Indicates the bundlePath.
459      */
460     void DeletePreInfoInDb(
461         const std::string &bundleName, const std::string &bundlePath, bool bundleLevel);
462     /**
463      * @brief Add parseInfos to map.
464      * @param bundleName Indicates the bundleName.
465      * @param infos Indicates the infos.
466      */
467     void AddParseInfosToMap(const std::string &bundleName,
468         const std::unordered_map<std::string, InnerBundleInfo> &infos);
469     /**
470      * @brief Clear cache.
471      */
472     void ClearCache();
473     /**
474      * @brief Judge whether the preInstall app can be removable.
475      * @param path Indicates the path.
476      * @return Returns true if the preInstall is removable; returns false otherwise.
477      */
478     bool IsPreInstallRemovable(const std::string &path);
479 
480     void AddTasks(const std::map<int32_t, std::vector<PreScanInfo>,
481         std::greater<int32_t>> &taskMap, int32_t userId);
482     void AddTaskParallel(
483         int32_t taskPriority, const std::vector<PreScanInfo> &tasks, int32_t userId);
484 
485     bool InnerMultiProcessBundleInstall(
486         const std::unordered_map<std::string, std::pair<std::string, bool>> &needInstallMap,
487         Constants::AppType appType);
488 
489     bool CheckOtaFlag(OTAFlag flag, bool &result);
490     bool UpdateOtaFlag(OTAFlag flag);
491     void ProcessCheckAppDataDir();
492     void InnerProcessCheckAppDataDir();
493 
494     void ProcessCheckAppLogDir();
495     void InnerProcessCheckAppLogDir();
496     void ProcessCheckAppFileManagerDir();
497     void InnerProcessCheckAppFileManagerDir();
498     void ProcessCheckPreinstallData();
499     void InnerProcessCheckPreinstallData();
500     void ProcessCheckShaderCacheDir();
501     void InnerProcessCheckShaderCacheDir();
502     void ProcessCheckCloudShaderDir();
503     void InnerProcessCheckCloudShaderDir();
504     void ProcessNewBackupDir();
505     void ProcessCheckRecoverableApplicationInfo();
506     void InnerProcessCheckRecoverableApplicationInfo();
507 
508     bool InnerProcessUninstallForExistPreBundle(const BundleInfo &installedInfo);
509 
510     void PrepareBundleDirQuota(const std::string &bundleName, const int32_t uid,
511         const std::string &bundleDataDirPath, const int32_t limitSize) const;
512     void RefreshQuotaForAllUid();
513 
514     bool InnerProcessUninstallModule(const BundleInfo &bundleInfo,
515         const std::unordered_map<std::string, InnerBundleInfo> &infos);
516 
517     bool IsSystemUpgrade();
518     bool IsTestSystemUpgrade();
519     bool IsSystemFingerprintChanged();
520     std::string GetCurSystemFingerprint();
521     std::string GetOldSystemFingerprint();
522     bool GetSystemParameter(const std::string &key, std::string &value);
523     void SaveSystemFingerprint();
524     void HandlePreInstallException();
525     static bool IsHapPathExist(const BundleInfo &bundleInfo);
526     static bool IsHspPathExist(const InnerBundleInfo &innerBundleInfo);
527 
528     bool FetchInnerBundleInfo(const std::string &bundleName, InnerBundleInfo &innerBundleInfo);
529     void GetPreInstallDirFromLoadProFile(std::vector<std::string> &bundleDirs);
530     void GetPreInstallDirFromScan(std::vector<std::string> &bundleDirs);
531 
532     void InnerProcessBootSystemHspInstall();
533     void ProcessSystemHspInstall(const PreScanInfo &preScanInfo);
534 
535     void AddStockAppProvisionInfoByOTA(const std::string &bundleName, const std::string &filePath);
536     void UpdateAppDataSelinuxLabel(const std::string &bundleName, const std::string &apl,
537         bool isPreInstall, bool debug);
538     static bool IsQuickfixFlagExsit(const BundleInfo &bundleInfo);
539     static bool GetValueFromJson(nlohmann::json &jsonObject);
540     static void PatchSystemHspInstall(const std::string &path, bool isOta);
541     static void PatchSystemBundleInstall(const std::string &path, bool isOta);
542 #ifdef USE_PRE_BUNDLE_PROFILE
543     void UpdateRemovable(const std::string &bundleName, bool removable);
544     void UpdateAllPrivilegeCapability();
545     void UpdatePrivilegeCapability(const PreBundleConfigInfo &preBundleConfigInfo);
546     bool MatchSignature(const PreBundleConfigInfo &configInfo, const std::string &signature);
547     bool MatchOldSignatures(const PreBundleConfigInfo &configInfo, const std::vector<std::string> &appSignatures);
548     void UpdateTrustedPrivilegeCapability(const PreBundleConfigInfo &preBundleConfigInfo);
549 #endif
550     void ListeningUserUnlocked() const;
551     void RemoveUnreservedSandbox() const;
552     void HandleSceneBoard() const;
553     void InnerProcessStockBundleProvisionInfo();
554     void ProcessBundleProvisionInfo(const std::unordered_set<std::string> &allBundleNames);
555     void ProcessSharedBundleProvisionInfo(const std::unordered_set<std::string> &allBundleNames);
556     bool UpdateModuleByHash(const BundleInfo &oldBundleInfo, const InnerBundleInfo &newInfo) const;
557     bool IsNeedToUpdateSharedAppByHash(const InnerBundleInfo &oldInfo, const InnerBundleInfo &newInfo) const;
558     void CheckALLResourceInfo();
559     // Used to add bundle resource Info that does not exist in rdb when OTA.
560     void static ProcessBundleResourceInfo();
561     // scan all bundle data group info
562     void ProcessAllBundleDataGroupInfo();
563     // Used to send update failed event
564     void SendBundleUpdateFailedEvent(const BundleInfo &bundleInfo);
565     void UpdatePreinstallDB(const std::unordered_map<std::string, std::pair<std::string, bool>> &needInstallMap);
566     void UpdatePreinstallDBForNotUpdatedBundle(const std::string &bundleName,
567         const std::unordered_map<std::string, InnerBundleInfo> &innerBundleInfos);
568     void InnerProcessRebootUninstallWrongBundle();
569     void ProcessCheckAppEl1Dir();
570     void static ProcessCheckAppEl1DirTask();
571     void CleanAllBundleShaderCache() const;
572     // Used to save the information parsed by Hap in the scanned directory.
573     std::map<std::string, std::unordered_map<std::string, InnerBundleInfo>> hapParseInfoMap_;
574     // Used to save application information that already exists in the Db.
575     std::map<std::string, PreInstallBundleInfo> loadExistData_;
576     // Used to mark Whether trigger OTA check
577     bool needRebootOta_ = false;
578     // Used to notify bundle scan status
579     bool needNotifyBundleScanStatus_ = false;
580 
581     bool hasLoadAllPreInstallBundleInfosFromDb_ = false;
582 };
583 }  // namespace AppExecFwk
584 }  // namespace OHOS
585 #endif  // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_BUNDLE_MGR_SERVICE_EVENT_HANDLER_H
586