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 OHOS_ABILITY_RUNTIME_MISSION_LIST_MANAGER_H 17 #define OHOS_ABILITY_RUNTIME_MISSION_LIST_MANAGER_H 18 19 #include <list> 20 #include <mutex> 21 #include <queue> 22 #include <memory> 23 #include "cpp/mutex.h" 24 25 #include "ability_running_info.h" 26 #include "foundation/distributedhardware/device_manager/interfaces/inner_kits/native_cpp/include/device_manager.h" 27 #include "mission_list.h" 28 #include "mission_listener_controller.h" 29 #include "mission_info.h" 30 #include "mission_snapshot.h" 31 #include "snapshot.h" 32 #include "start_options.h" 33 #include "want.h" 34 #include "iability_info_callback.h" 35 36 namespace OHOS { 37 namespace AAFwk { 38 class MissionListManager : public std::enable_shared_from_this<MissionListManager> { 39 public: 40 explicit MissionListManager(int userId); 41 ~MissionListManager(); 42 43 /** 44 * init ability mission manager. 45 * 46 */ 47 void Init(); 48 49 /** 50 * StartAbility with request. 51 * 52 * @param abilityRequest, the request of the service ability to start. 53 * @return Returns ERR_OK on success, others on failure. 54 */ 55 int StartAbility(AbilityRequest &abilityRequest); 56 57 /** 58 * MinimizeAbility, minimize the special ability. 59 * 60 * @param token, ability token. 61 * @param fromUser mark the minimize operation source. 62 * @return Returns ERR_OK on success, others on failure. 63 */ 64 int MinimizeAbility(const sptr<IRemoteObject> &token, bool fromUser); 65 66 int RegisterMissionListener(const sptr<IMissionListener> &listener); 67 68 int UnRegisterMissionListener(const sptr<IMissionListener> &listener); 69 70 int GetMissionInfos(int32_t numMax, std::vector<MissionInfo> &missionInfos); 71 72 int GetMissionInfo(int32_t missionId, MissionInfo &missionInfo); 73 74 int MoveMissionToFront(int32_t missionId, std::shared_ptr<StartOptions> startOptions = nullptr); 75 76 int MoveMissionToFront(int32_t missionId, bool isCallerFromLauncher, bool isRecent, 77 std::shared_ptr<AbilityRecord> callerAbility, std::shared_ptr<StartOptions> startOptions = nullptr); 78 79 void NotifyMissionFocused(const int32_t missionId); 80 81 void NotifyMissionUnfocused(const int32_t missionId); 82 83 /** 84 * OnAbilityRequestDone, app manager service call this interface after ability request done. 85 * 86 * @param token,ability's token. 87 * @param state,the state of ability lift cycle. 88 */ 89 void OnAbilityRequestDone(const sptr<IRemoteObject> &token, const int32_t state); 90 91 void OnAppStateChanged(const AppInfo &info); 92 93 /** 94 * attach ability thread ipc object. 95 * 96 * @param scheduler, ability thread ipc object. 97 * @param token, the token of ability. 98 * @return Returns ERR_OK on success, others on failure. 99 */ 100 int AttachAbilityThread(const sptr<AAFwk::IAbilityScheduler> &scheduler, const sptr<IRemoteObject> &token); 101 102 /** 103 * start waiting ability. 104 */ 105 void StartWaitingAbility(); 106 107 /** 108 * @brief Get the Ability Record By Token object 109 * 110 * @param token the search token 111 * @return std::shared_ptr<AbilityRecord> the AbilityRecord of the token 112 */ 113 std::shared_ptr<AbilityRecord> GetAbilityRecordByToken(const sptr<IRemoteObject> &token) const; 114 115 /** 116 * @brief Get the Mission By Id object 117 * 118 * @param missionId the given missionId 119 * @return the mission of the given id 120 */ 121 std::shared_ptr<Mission> GetMissionById(int missionId) const; 122 123 /** 124 * @brief Move ability to background with the given abilityRecord 125 * 126 * @param abilityRecord the ability to move 127 * @return int error code 128 */ 129 int MoveAbilityToBackground(const std::shared_ptr<AbilityRecord> &abilityRecord); 130 131 /** 132 * @brief Terminate ability with the given abilityRecord 133 * 134 * @param abilityRecord the ability to terminate 135 * @param resultCode the terminate data 136 * @param resultWant the terminate data 137 * @param flag mark terminate flag 138 * @return int error code 139 */ 140 int TerminateAbility(const std::shared_ptr<AbilityRecord> &abilityRecord, 141 int resultCode, const Want *resultWant, bool flag); 142 143 /** 144 * @brief remove the mission list from the mission list manager 145 * 146 * @param MissionList the mission list need to remove 147 */ 148 void RemoveMissionList(const std::shared_ptr<MissionList> &MissionList); 149 150 /** 151 * @brief execute after the ability schedule the lifecycle 152 * 153 * @param token the ability token 154 * @param state the ability state 155 * @param saveData the saved data 156 * @return execute error code 157 */ 158 int AbilityTransactionDone(const sptr<IRemoteObject> &token, int state, const PacMap &saveData); 159 160 /** 161 * @brief search the ability from terminating list 162 * 163 * @param token the ability token 164 * @return the ability need to terminate 165 */ 166 std::shared_ptr<AbilityRecord> GetAbilityFromTerminateList(const sptr<IRemoteObject> &token); 167 168 /** 169 * @brief clear the mission with the given id 170 * 171 * @param missionId the mission need to delete 172 * @return int error code 173 */ 174 int ClearMission(int missionId); 175 176 /** 177 * @brief clear all the missions 178 * 179 * @return int error code 180 */ 181 int ClearAllMissions(); 182 183 void ClearAllMissionsLocked(std::list<std::shared_ptr<Mission>> &missionList, 184 std::list<std::shared_ptr<Mission>> &foregroundAbilities, bool searchActive); 185 186 /** 187 * @brief Set the Mission Locked State object 188 * 189 * @param missionId the id of the mission 190 * @return int error code 191 */ 192 int SetMissionLockedState(int missionId, bool lockedState); 193 194 /** 195 * @brief schedule to background 196 * 197 * @param abilityRecord the ability to move 198 */ 199 void MoveToBackgroundTask(const std::shared_ptr<AbilityRecord> &abilityRecord, bool isClose = false); 200 201 /** 202 * @brief handle time out event 203 * 204 * @param msgId the msg id in ability record 205 * @param abilityRecordId the id of ability record 206 * @param isHalf is half 207 */ 208 void OnTimeOut(uint32_t msgId, int64_t abilityRecordId, bool isHalf = false); 209 210 /** 211 * @brief handle when ability died 212 * 213 * @param abilityRecord the died ability 214 */ 215 void OnAbilityDied(std::shared_ptr<AbilityRecord> abilityRecord, int32_t currentUserId); 216 217 /** 218 * @brief handle when call connection died 219 * 220 * @param callRecord the died call connection 221 */ 222 void OnCallConnectDied(const std::shared_ptr<CallRecord> &callRecord); 223 224 /** 225 * Get mission id by target ability token. 226 * 227 * @param token target ability token. 228 * @return the missionId of target mission. 229 */ 230 int32_t GetMissionIdByAbilityToken(const sptr<IRemoteObject> &token); 231 232 /** 233 * Get ability token by target mission id. 234 * 235 * @param missionId target missionId. 236 * @return the ability token of target mission. 237 */ 238 sptr<IRemoteObject> GetAbilityTokenByMissionId(int32_t missionId); 239 240 /** 241 * @brief dump all abilities 242 * 243 * @param info dump result. 244 */ 245 void Dump(std::vector<std::string>& info); 246 247 /** 248 * @brief dump mission list 249 * 250 * @param info dump result. 251 */ 252 void DumpMissionList(std::vector<std::string> &info, bool isClient, const std::string &args = ""); 253 254 /** 255 * @brief dump mission list by id with params 256 * 257 * @param info dump result. 258 * @param params dump params. 259 */ 260 void DumpMissionListByRecordId( 261 std::vector<std::string>& info, bool isClient, int32_t abilityRecordId, const std::vector<std::string>& params); 262 263 /** 264 * @brief dump mission by id 265 * 266 * @param info dump result. 267 */ 268 void DumpMission(int missionId, std::vector<std::string> &info); 269 270 /** 271 * @brief dump mission infos 272 * 273 * @param info dump result. 274 */ 275 void DumpMissionInfos(std::vector<std::string> &info); 276 277 void OnAcceptWantResponse(const AAFwk::Want &want, const std::string &flag); 278 279 void OnStartSpecifiedAbilityTimeoutResponse(const AAFwk::Want &want); 280 /** 281 * resolve the call ipc of ability for scheduling oncall. 282 * 283 * @param abilityRequest, target ability request. 284 */ 285 int ResolveLocked(const AbilityRequest &abilityRequest); 286 287 /** 288 * release the connection of this call. 289 * 290 * @param connect, caller callback ipc. 291 * @param element, target ability name. 292 */ 293 int ReleaseCallLocked(const sptr<IAbilityConnection> &connect, const AppExecFwk::ElementName &element); 294 /** 295 * @brief register snapshotHandler 296 * @param handler the snapshotHandler 297 */ 298 void RegisterSnapshotHandler(const sptr<ISnapshotHandler>& handler); 299 300 /** 301 * @brief Get the Mission Snapshot object 302 * @param missionId mission id 303 * @param abilityToken abilityToken to get current mission snapshot 304 * @param missionSnapshot result of snapshot 305 * @param isLowResolution low resolution. 306 * @return Returns true on success, false on failure. 307 */ 308 bool GetMissionSnapshot(int32_t missionId, const sptr<IRemoteObject>& abilityToken, 309 MissionSnapshot& missionSnapshot, bool isLowResolution); 310 void GetAbilityRunningInfos(std::vector<AbilityRunningInfo> &info, bool isPerm); 311 312 /** 313 * Called to update mission snapshot. 314 * @param token The target ability. 315 * @param pixelMap The snapshot. 316 */ 317 void UpdateSnapShot(const sptr<IRemoteObject> &token, const std::shared_ptr<Media::PixelMap> &pixelMap); 318 319 void EnableRecoverAbility(int32_t missionId); 320 321 #ifdef ABILITY_COMMAND_FOR_TEST 322 /** 323 * Block ability. 324 * 325 * @param abilityRecordId The Ability Record Id. 326 * @return Returns ERR_OK on success, others on failure. 327 */ 328 int BlockAbility(int abilityRecordId); 329 #endif 330 331 void UninstallApp(const std::string &bundleName, int32_t uid); 332 333 bool IsStarted(); 334 void PauseManager(); 335 void ResumeManager(); 336 337 void SetMissionANRStateByTokens(const std::vector<sptr<IRemoteObject>> &tokens); 338 339 int32_t IsValidMissionIds(const std::vector<int32_t> &missionIds, std::vector<MissionVaildResult> &results); 340 341 int DoAbilityForeground(std::shared_ptr<AbilityRecord> &abilityRecord, uint32_t flag); 342 343 void GetActiveAbilityList(const std::string &bundleName, std::vector<std::string> &abilityList); 344 345 void CallRequestDone(const std::shared_ptr<AbilityRecord> &abilityRecord, const sptr<IRemoteObject> &callStub); 346 347 int SetMissionContinueState(const sptr<IRemoteObject> &token, const int32_t missionId, 348 const AAFwk::ContinueState &state); 349 350 int32_t MoveMissionToBackground(int32_t missionId); 351 #ifdef SUPPORT_GRAPHICS 352 public: 353 /** 354 * Set mission label of this ability. 355 * 356 * @param abilityToken target ability token. 357 * @param label target label. 358 * @return Return 0 if success. 359 */ 360 int SetMissionLabel(const sptr<IRemoteObject> &abilityToken, const std::string &label); 361 362 /** 363 * Set mission icon of this ability. 364 * 365 * @param token target ability token. 366 * @param icon target label. 367 * @return Return 0 if success. 368 */ 369 int SetMissionIcon(const sptr<IRemoteObject> &token, const std::shared_ptr<Media::PixelMap> &icon); 370 371 void CompleteFirstFrameDrawing(const sptr<IRemoteObject> &abilityToken) const; 372 373 void PostMissionLabelUpdateTask(int missionId) const; 374 375 int32_t TerminateMission(int32_t missionId); 376 377 private: 378 Closure GetCancelStartingWindowTask(const std::shared_ptr<AbilityRecord> &abilityRecord) const; 379 void PostCancelStartingWindowTask(const std::shared_ptr<AbilityRecord> &abilityRecord) const; 380 void InitPrepareTerminateConfig(); 381 #endif 382 383 private: 384 int StartAbilityLocked(const std::shared_ptr<AbilityRecord> ¤tTopAbility, 385 const std::shared_ptr<AbilityRecord> &callerAbility, const AbilityRequest &abilityRequest); 386 int StartAbility(const std::shared_ptr<AbilityRecord> ¤tTopAbility, 387 const std::shared_ptr<AbilityRecord> &callerAbility, const AbilityRequest &abilityRequest); 388 int MinimizeAbilityLocked(const std::shared_ptr<AbilityRecord> &abilityRecord, bool fromUser); 389 std::shared_ptr<AbilityRecord> GetCurrentTopAbilityLocked() const; 390 std::shared_ptr<MissionList> GetTargetMissionList( 391 const std::shared_ptr<AbilityRecord> &callerAbility, const AbilityRequest &abilityRequest); 392 std::shared_ptr<MissionList> GetTargetMissionListByLauncher(const AbilityRequest &abilityRequest); 393 std::shared_ptr<MissionList> GetTargetMissionListByDefault( 394 const std::shared_ptr<AbilityRecord> &callerAbility, const AbilityRequest &abilityRequest); 395 std::shared_ptr<Mission> GetReusedMission(const AbilityRequest &abilityRequest); 396 std::shared_ptr<Mission> GetReusedSpecifiedMission(const AbilityRequest &abilityRequest); 397 std::shared_ptr<Mission> GetReusedStandardMission(const AbilityRequest &abilityRequest); 398 void GetTargetMissionAndAbility(const AbilityRequest &abilityRequest, std::shared_ptr<Mission> &targetMission, 399 std::shared_ptr<AbilityRecord> &targetRecord, bool &isReachToLimit); 400 bool HandleReusedMissionAndAbility(const AbilityRequest &abilityRequest, std::shared_ptr<Mission> &targetMission, 401 std::shared_ptr<AbilityRecord> &targetRecord); 402 std::string GetMissionName(const AbilityRequest &abilityRequest) const; 403 bool CreateOrReusedMissionInfo(const AbilityRequest &abilityRequest, InnerMissionInfo &info) const; 404 void MoveMissionToTargetList(bool isCallFromLauncher, 405 const std::shared_ptr<MissionList> &targetMissionList, 406 const std::shared_ptr<Mission> &mission); 407 void MoveMissionListToTop(const std::shared_ptr<MissionList> &missionList); 408 void MoveNoneTopMissionToDefaultList(const std::shared_ptr<Mission> &mission); 409 void PrintTimeOutLog(const std::shared_ptr<AbilityRecord> &ability, uint32_t msgId, bool isHalf = false); 410 411 int DispatchState(const std::shared_ptr<AbilityRecord> &abilityRecord, int state); 412 int DispatchForeground(const std::shared_ptr<AbilityRecord> &abilityRecord, bool success, 413 AbilityState state = AbilityState::INITIAL); 414 int DispatchTerminate(const std::shared_ptr<AbilityRecord> &abilityRecord); 415 int DispatchBackground(const std::shared_ptr<AbilityRecord> &abilityRecord); 416 void CompleteForegroundSuccess(const std::shared_ptr<AbilityRecord> &abilityRecord); 417 void CompleteTerminate(const std::shared_ptr<AbilityRecord> &abilityRecord); 418 void DelayCompleteTerminate(const std::shared_ptr<AbilityRecord> &abilityRecord); 419 void CompleteBackground(const std::shared_ptr<AbilityRecord> &abilityRecord); 420 void CompleteTerminateAndUpdateMission(const std::shared_ptr<AbilityRecord> &abilityRecord); 421 bool RemoveMissionList(const std::list<std::shared_ptr<MissionList>> lists, 422 const std::shared_ptr<MissionList> &list); 423 int ClearMissionLocked(int missionId, const std::shared_ptr<Mission> &mission); 424 int ClearMissionLocking(int missionId, const std::shared_ptr<Mission> &mission); 425 int MoveAbilityToBackgroundLocked(const std::shared_ptr<AbilityRecord> &abilityRecord); 426 void RemoveBackgroundingAbility(const std::shared_ptr<AbilityRecord> &abilityRecord); 427 int TerminateAbilityLocked(const std::shared_ptr<AbilityRecord> &abilityRecord, bool flag); 428 /** 429 * @brief remove the mission from the mission list 430 * 431 * @param abilityRecord the ability need to remove 432 * @param flag mark is terminate or close 433 */ 434 void RemoveTerminatingAbility(const std::shared_ptr<AbilityRecord> &abilityRecord, bool flag); 435 std::shared_ptr<AbilityRecord> GetAbilityRecordById(int64_t abilityRecordId) const; 436 std::shared_ptr<AbilityRecord> GetAbilityRecordByCaller( 437 const std::shared_ptr<AbilityRecord> &caller, int requestCode); 438 std::shared_ptr<MissionList> GetTargetMissionList(int missionId, std::shared_ptr<Mission> &mission, 439 bool &isReachToLimit); 440 void PostStartWaitingAbility(); 441 void HandleAbilityDied(std::shared_ptr<AbilityRecord> abilityRecord); 442 void HandleLauncherDied(std::shared_ptr<AbilityRecord> ability); 443 void HandleAbilityDiedByDefault(std::shared_ptr<AbilityRecord> abilityRecord); 444 void DelayedStartLauncher(); 445 void BackToLauncher(); 446 void GetAllForegroundAbilities(std::list<std::shared_ptr<AbilityRecord>>& foregroundList); 447 void GetForegroundAbilities(const std::shared_ptr<MissionList>& missionList, 448 std::list<std::shared_ptr<AbilityRecord>>& foregroundList); 449 std::shared_ptr<Mission> GetMissionBySpecifiedFlag(const AAFwk::Want &want, const std::string &flag) const; 450 bool IsReachToSingleLimitLocked(const int32_t uid) const; 451 bool IsReachToLimitLocked() const; 452 bool CheckSingleLimit(const AbilityRequest &abilityRequest); 453 bool CheckLimit(); 454 std::shared_ptr<Mission> FindEarliestMission() const; 455 int32_t GetMissionCount() const; 456 457 // handle timeout event 458 void HandleLoadTimeout(const std::shared_ptr<AbilityRecord> &ability); 459 void HandleForegroundTimeout(const std::shared_ptr<AbilityRecord> &ability, 460 AbilityState state = AbilityState::INITIAL); 461 void HandleTimeoutAndResumeAbility(const std::shared_ptr<AbilityRecord> &ability, 462 AbilityState state = AbilityState::INITIAL); 463 void MoveToTerminateList(const std::shared_ptr<AbilityRecord> &ability); 464 void DelayedResumeTimeout(const std::shared_ptr<AbilityRecord> &callerAbility); 465 void BackToCaller(const std::shared_ptr<AbilityRecord> &callerAbility); 466 467 // new version for call inner function. 468 void CompleteForegroundFailed(const std::shared_ptr<AbilityRecord> &abilityRecord, AbilityState state); 469 int ResolveAbility(const std::shared_ptr<AbilityRecord> &targetAbility, const AbilityRequest &abilityRequest); 470 std::shared_ptr<AbilityRecord> GetAbilityRecordByName(const AppExecFwk::ElementName &element); 471 std::vector<std::shared_ptr<AbilityRecord>> GetAbilityRecordsByName(const AppExecFwk::ElementName &element); 472 int CallAbilityLocked(const AbilityRequest &abilityRequest); 473 void UpdateMissionSnapshot(const std::shared_ptr<AbilityRecord> &abilityRecord) const; 474 void AddUninstallTags(const std::string &bundleName, int32_t uid); 475 void EraseWaitingAbility(const std::string &bundleName, int32_t uid); 476 void RemoveMissionLocked(int32_t missionId, bool excludeFromMissions); 477 void TerminatePreviousAbility(const std::shared_ptr<AbilityRecord> &abilityRecord); 478 void NotifyMissionCreated(const std::shared_ptr<AbilityRecord> &abilityRecord) const; 479 bool IsExcludeFromMissions(const std::shared_ptr<Mission> &mission); 480 void BuildInnerMissionInfo(InnerMissionInfo &info, const std::string &missionName, 481 const std::string &missionAffinity, const AbilityRequest &abilityRequest) const; 482 void NotifyStartSpecifiedAbility(AbilityRequest &request, const AAFwk::Want &want); 483 void NotifyRestartSpecifiedAbility(AbilityRequest &request, const sptr<IRemoteObject> &token); 484 void ProcessPreload(const std::shared_ptr<AbilityRecord> &record) const; 485 bool UpdateAbilityRecordLaunchReason( 486 const AbilityRequest &abilityRequest, std::shared_ptr<AbilityRecord> &targetAbilityRecord); 487 std::shared_ptr<AbilityRecord> GetAliveAbilityRecordByToken(const sptr<IRemoteObject> &token) const; 488 void NotifyAbilityToken(const sptr<IRemoteObject> &token, const AbilityRequest &abilityRequest); 489 void NotifyStartAbilityResult(const AbilityRequest &abilityRequest, int result); 490 int MoveMissionToFrontInner(int32_t missionId, bool isCallerFromLauncher, bool isRecent, 491 std::shared_ptr<AbilityRecord> callerAbility, std::shared_ptr<StartOptions> startOptions = nullptr); 492 /** 493 * push waiting ability to queue. 494 * 495 * @param abilityRequest, the request of ability. 496 */ 497 void EnqueueWaitingAbility(const AbilityRequest &abilityRequest); 498 499 /** 500 * push front waiting ability to queue. 501 * 502 * @param abilityRequest, the request of ability. 503 */ 504 void EnqueueWaitingAbilityToFront(const AbilityRequest &abilityRequest); 505 std::shared_ptr<AbilityRecord> GetAbilityRecordByTokenInner(const sptr<IRemoteObject> &token) const; 506 int TerminateAbilityInner(const std::shared_ptr<AbilityRecord> &abilityRecord, 507 int resultCode, const Want *resultWant, bool flag); 508 int32_t GetMissionIdByAbilityTokenInner(const sptr<IRemoteObject> &token); 509 std::shared_ptr<AbilityRecord> GetAbilityFromTerminateListInner(const sptr<IRemoteObject> &token); 510 void SetLastExitReason(std::shared_ptr<AbilityRecord> &abilityRecord); 511 LastExitReason CovertAppExitReasonToLastReason(const Reason exitReason); 512 bool IsAppLastAbility(const std::shared_ptr<AbilityRecord> &abilityRecord); 513 514 int PrepareClearMissionLocked(int missionId, const std::shared_ptr<Mission> &mission); 515 516 bool CheckPrepareTerminateEnable(const std::shared_ptr<Mission> &mission); 517 518 void NotifyCollaboratorMissionCreated(const AbilityRequest &abilityRequest, 519 const std::shared_ptr<Mission> &targetMission, InnerMissionInfo &info); 520 521 int userId_; 522 mutable ffrt::mutex managerLock_; 523 // launcher list is also in currentMissionLists_ 524 std::list<std::shared_ptr<MissionList>> currentMissionLists_; 525 // only manager the ability of standard in the default list 526 std::shared_ptr<MissionList> defaultStandardList_; 527 // only manager the ability of singleton in the default list for the fast search 528 std::shared_ptr<MissionList> defaultSingleList_; 529 std::shared_ptr<MissionList> launcherList_; 530 std::list<std::shared_ptr<AbilityRecord>> terminateAbilityList_; 531 532 std::queue<AbilityRequest> waitingAbilityQueue_; 533 std::shared_ptr<MissionListenerController> listenerController_; 534 bool isPrepareTerminateEnable_ = false; 535 536 class MissionDmInitCallback : public DistributedHardware::DmInitCallback { 537 public: 538 void OnRemoteDied() override; 539 540 static bool isInit_; 541 }; 542 }; 543 } // namespace AAFwk 544 } // namespace OHOS 545 #endif // OHOS_ABILITY_RUNTIME_MISSION_LIST_MANAGER_H 546