From 2becc40592dc88044ff6737c4c0ef0e276ed2d76 Mon Sep 17 00:00:00 2001 From: yaoruozi Date: Thu, 4 Sep 2025 20:59:37 +0800 Subject: [PATCH] uninstall cloudstorage and remove syncroot Signed-off-by: yaoruozi --- services/5010.json | 17 +- services/BUILD.gn | 18 + services/file_access_service.para | 14 + services/ile_access_service.para.dac | 14 + .../include/bundle_observer.h | 46 ++ .../include/file_access_service.h | 22 +- .../src/bundle_observer.cpp | 144 ++++++ .../src/file_access_service.cpp | 81 +++- test/unittest/BUILD.gn | 65 +++ test/unittest/bundle_observer_test.cpp | 324 ++++++++++++++ test/unittest/file_access_service_test.cpp | 418 ++++++++++++++++++ .../mock/file_access_service_mock.cpp | 23 + test/unittest/mock/file_access_service_mock.h | 17 + 13 files changed, 1187 insertions(+), 16 deletions(-) create mode 100644 services/file_access_service.para create mode 100644 services/ile_access_service.para.dac create mode 100644 services/native/file_access_service/include/bundle_observer.h create mode 100644 services/native/file_access_service/src/bundle_observer.cpp create mode 100644 test/unittest/bundle_observer_test.cpp create mode 100644 test/unittest/file_access_service_test.cpp create mode 100644 test/unittest/mock/file_access_service_mock.cpp diff --git a/services/5010.json b/services/5010.json index 8f40348d..dd7e0070 100755 --- a/services/5010.json +++ b/services/5010.json @@ -6,7 +6,22 @@ "libpath": "libfile_access_service.z.so", "run-on-create": false, "distributed": false, - "dump_level": 1 + "dump_level": 1, + "cache-common-event":true, + "start-on-demand": { + "commonevent": [ + { + "name": "usual.event.PACKAGE_REMOVED", + "conditions": [ + { + "eventId": "param", + "name": "persist.clouddiskmanager.workstatus", + "value": "true" + } + ] + } + ] + } } ] } \ No newline at end of file diff --git a/services/BUILD.gn b/services/BUILD.gn index d0441abd..89cc3f0c 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -180,6 +180,7 @@ ohos_shared_library("file_access_service") { shlib_type = "sa" sources = [ "${user_file_service_path}/interfaces/inner_api/file_access/src/uri_ext.cpp", + "native/file_access_service/src/bundle_observer.cpp", "native/file_access_service/src/file_access_ext_connection.cpp", "native/file_access_service/src/file_access_service.cpp", "native/file_access_service/src/file_access_service_client.cpp", @@ -192,6 +193,8 @@ ohos_shared_library("file_access_service") { ":file_access_service_base_source", "${user_file_service_path}/interfaces/inner_api/file_access:file_access_ext_base_include", "${user_file_service_path}/interfaces/inner_api/file_access:file_access_extension_ability_kit", + ":file_access_service.para", + ":file_access_service.para.dac", ] external_deps = [ @@ -214,3 +217,18 @@ ohos_shared_library("file_access_service") { subsystem_name = "filemanagement" part_name = "user_file_service" } + +ohos_prebuilt_etc("file_access_service.para") { + source = "file_access_service.para" + part_name = "user_file_service" + module_install_dir = "etc/param" + subsystem_name = "filemanagement" +} + +ohos_prebuilt_etc("file_access_service.para.dac") { + source = "file_access_service.para.dac" + part_name = "user_file_service" + module_install_dir = "etc/param" + subsystem_name = "filemanagement" +} + diff --git a/services/file_access_service.para b/services/file_access_service.para new file mode 100644 index 00000000..adecb4f4 --- /dev/null +++ b/services/file_access_service.para @@ -0,0 +1,14 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +persist.clouddiskmanager.workstatus = true \ No newline at end of file diff --git a/services/ile_access_service.para.dac b/services/ile_access_service.para.dac new file mode 100644 index 00000000..efa13ef4 --- /dev/null +++ b/services/ile_access_service.para.dac @@ -0,0 +1,14 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +persist.clouddiskmanager.workstatus = file_manager:file_manager:0776 \ No newline at end of file diff --git a/services/native/file_access_service/include/bundle_observer.h b/services/native/file_access_service/include/bundle_observer.h new file mode 100644 index 00000000..1638301c --- /dev/null +++ b/services/native/file_access_service/include/bundle_observer.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + #ifndef BUNDLE_OBSERVER_H + #define BUNDLE_OBSERVER_H + + #include + #include + #include + + #include "common_event_subscriber_info.h" + #include "common_event_subscriber.h" + #include "system_ability_ondemand_reason.h" + + +namespace OHOS { +namespace FileAccessFwk { +using namespace std; + +class BundleObserver final: public EventFwk::CommonEventSubscriber { +public: + BundleObserver() = default; + ~BundleObserver(); + + static int32_t HandleBundleBroadcast(); + static int32_t ClearSyncFolder(const string &bundleName, int32_t userId, int32_t appIndex); + static string GetValueByKey(const std::map &map, const string &key); + static int32_t GetNumberFromString(const string &str, const int32_t defaultValue); + + explicit BundleObserver(const EventFwk::CommonEventSubscribeInfo &subscribeInfo); + virtual void OnReceiveEvent(const EventFwk::CommonEventData &data) override; +} +} // namespace FileAccessFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/native/file_access_service/include/file_access_service.h b/services/native/file_access_service/include/file_access_service.h index b24e0c47..2a129304 100644 --- a/services/native/file_access_service/include/file_access_service.h +++ b/services/native/file_access_service/include/file_access_service.h @@ -24,14 +24,18 @@ #include #include -#include "file_access_helper.h" +#include "bundle_observer.h" #include "bundle_mgr_interface.h" +#include "common_event_manager.h" +#include "common_event_support.h" +#include "file_access_helper.h" #include "file_access_ext_connection.h" #include "file_access_service_base_stub.h" #include "ifile_access_ext_base.h" #include "holder_manager.h" #include "ifile_access_ext_base.h" #include "iremote_object.h" +#include "thread_pool.h" #include "timer.h" #include "uri.h" #include "want.h" @@ -223,12 +227,16 @@ public: bool CheckCallingPermission(const std::string &permission); static sptr GetInstance(); void Init(); - virtual ~FileAccessService() = default; + ~FileAccessService(); virtual void OnStart() override; + virtual void OnStart(const SystemAbilityOnDemandReason &startReason) override; virtual void OnStop() override; + + void OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId) override; + void OnRemoveSystemAbility(int32_t systemAbilityId, const std::string &deviceId) override; int32_t Dump(int32_t fd, const std::vector &args) override; - + void DisconnectAppProxy(const sptr& connection); void RemoveAppProxy(const sptr& connection); @@ -298,7 +306,7 @@ private: HolderManager> obsManager_; std::mutex mapMutex_; std::unordered_map> cMap_; - + class AppDeathRecipient : public IRemoteObject::DeathRecipient { public: AppDeathRecipient() {} @@ -310,6 +318,12 @@ private: std::unordered_map> appProxyMap_; std::unordered_map> appConnection_; sptr appDeathRecipient_; + + void RegisterBundleBroadcast(); + void UnRegisterBundleBroadcast(); + + static inline std::shared_ptr bundleObserver_ = nullptr; + OHOS::ThreadPool handleBroadCastThreadPool_; }; } // namespace FileAccessFwk } // namespace OHOS diff --git a/services/native/file_access_service/src/bundle_observer.cpp b/services/native/file_access_service/src/bundle_observer.cpp new file mode 100644 index 00000000..79d63a2b --- /dev/null +++ b/services/native/file_access_service/src/bundle_observer.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2024-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bundle_observer.h" +#include "common_event_manager.h" +#include "common_event_support.h" +#include "hilog_wrapper.h" +#include "iservice_registry.h" +#include "notify_work_service.h" +#include "system_ability_definition.h" +#include "ufs_db_services_constants.h" +#include "ufs_rdb_adapter.h" + +namespace OHOS { +namespace FileAccessFwk { + +const int32_t SA_ID = 5010; +const int32_t APP_DEFAULT_INDEX = 0; +const int32_t USER_ID_DEFAULT = 100; + +BundleObserver::BundleObserver(const EventFwk::CommonEventSubscribeInfo &subscribeInfo) + :CommonEventSubscriber(subscribeInfo) +{ +} + +BundleObserver::~BundleObserver() +{ +} + +int32_t BundleObserver::HandleBundleBroadcast() +{ + HILOG_INFO("HandleBundleBroadcast Begin"); + auto saMgrPtr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (saMgrPtr == nullptr){ + HILOG_ERROR("saMgrPtr is nullptr"); + return ERR_INVALID_VALUE; + } + std::vector extraDataIdList; + int32_t ret = saMgrPtr->GetCommonEventExtraDataIdList(SA_ID, extraDataIdList, + EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED); + if (ret != ERR_OK) { + HILOG_ERROR("GetCommonEventExtraDataIdList failed, ret = %{public}d", ret); + return ret; + } + for (auto dataId : extraDataIdList) { + MessageParcel dataParcel; + int32_t getDataRet = saMgrPtr->GetOnDemandReasonExtraData(dataId, dataParcel); + if (getDataRet != ERR_OK) { + HILOG_ERROR("GetOnDemandReasonExtraData failed, ret = %{public}d", getDataRet); + continue; + } + auto extraData = dataParcel.ReadParcelable(); + if (extraData == nullptr) { + HILOG_ERROR("extraData is nullptr"); + continue; + } + map want = extraData->GetWant(); + string userIdStr = GetValueByKey(want, "userId"); + string bundleName = GetValueByKey(want, "bundleName"); + string appIndexStr = GetValueByKey(want, "appIndex"); + int32_t appIndex = GetNumberFromString(appIndexStr, APP_DEFAULT_INDEX); + int32_t userId = GetNumberFromString(userIdStr, USER_ID_DEFAULT); + ret = ClearSyncFolder(bundleName, userId, appIndex); + } + return ERR_OK; +} + +int32_t BundleObserver::ClearSyncFolder(const string &bundleName, int32_t userId, int32_t appIndex) +{ + HILOG_INFO("Begin ClearSyncRoot, bundleName: %{public}s, userId: %{public}d, appIndex: %{public}d", + bundleName.c_str(), userId, appIndex); + std::vector syncFolders; + SynchronousRootManager::GetInstance().GetRootInfosByUserAndBundle(bundleName, appIndex, userId, syncFolders); + if (syncFolders.empty()) { + HILOG_INFO("No sync root to clear"); + return ERR_INVALID_VALUE; + } + // 批量删除,后续逐条发广播,是否会有问题,保留 + // SynchronousRootManager::GetInstance().DeleteAllSynchronousRootsByUserAndBundle(bundleName, userId, appIndex); + for (const auto &folder : syncFolders) { + bool isDeleted = SynchronousRootManager::GetInstance().DeleteSynchronousRoot(folder.path_); + if (!isDeleted) { + HILOG_ERROR("Failed to delete sync root: %{public}s", folder.path_.c_str()); + continue; + } + SyncFolderExt syncFolderExt; + syncFolderExt.path_ = folder.path_; + syncFolderExt.bundleName_ = bundleName; + syncFolderExt.state_ = folder.state_; + syncFolderExt.displayName_ = folder.displayName_; + syncFolderExt.displayNameResId_ = folder.displayNameResId_; + NotifyWorkerService::GetInstance().NotifyRootInfoDetail(syncFolderExt, EventType::UNREGISTER); + } + return ERR_OK; +} + +void BundleObserver::OnReceiveEvent(const EventFwk::CommonEventData &data) +{ + HILOG_INFO("BundleObserver::OnReceiveEvent start"); + const OHOS::AAFwk::Want want = data.GetWant(); + string action = want.GetAction(); + if (action == EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED) { + OHOS::AAFwk::WantParams params = want.GetParams(); + int32_t userId = params.GetIntParam("userId", USER_ID_DEFAULT); + std::string bundleName = want.GetStringParam("bundleName"); + int32_t appIndex = params.GetIntParam("appIndex", APP_DEFAULT_INDEX); + int32_t ret = ClearSyncFolder(bundleName, userId, appIndex); + if (ret != 0) { + HILOG_ERROR("BundleObserver::OnReceiveEvent ClearSyncRoot failed"); + return; + } + } +} + +std::string BundleObserver::GetValueByKey(const std::map &map, const string &key) +{ + auto it = map.find(key); + if (it != map.end()) { + return it->second; + } + return ""; +} + +int32_t BundleObserver::GetNumberFromString(const string &str, const int32_t defaultValue) +{ + if (str.empty()) { + return defaultValue; + } + return static_cast(std::atoi(str.c_str())); +} +} // namespace FileAccessFwk +} // namespace OHOS \ No newline at end of file diff --git a/services/native/file_access_service/src/file_access_service.cpp b/services/native/file_access_service/src/file_access_service.cpp index e87c99cf..898faafe 100644 --- a/services/native/file_access_service/src/file_access_service.cpp +++ b/services/native/file_access_service/src/file_access_service.cpp @@ -18,17 +18,21 @@ #include #include -#include "user_access_tracer.h" +#include "access_token.h" +#include "accesstken_kit.h" +#include "common_event_manager.h" +#include "common_event_support.h" + #include "file_access_framework_errno.h" #include "file_access_extension_info.h" +#include "file_access_framework_errno.h" #include "hilog_wrapper.h" #include "hitrace_meter.h" #include "ipc_skeleton.h" -#include "system_ability_definition.h" #include "iservice_registry.h" +#include "system_ability_definition.h" #include "uri_ext.h" -#include "access_token.h" -#include "accesstoken_kit.h" +#include "user_access_tracer.h" using namespace std; namespace OHOS { @@ -47,6 +51,7 @@ constexpr int32_t NOTIFY_TIME_INTERVAL = 500; constexpr int32_t MAX_WAIT_TIME = 20; constexpr int32_t ONE_SECOND = 1 * 1000; constexpr int32_t UNLOAD_SA_WAIT_TIME = 30; +constexpr int32_t THREAD_NUM = 1 std::vector deviceUris(DEVICE_ROOTS.begin(), DEVICE_ROOTS.end()); bool FileAccessService::CheckCallingPermission(const std::string &permission) @@ -82,19 +87,21 @@ sptr FileAccessService::GetInstance() FileAccessService::FileAccessService() : SystemAbility(FILE_ACCESS_SERVICE_ID, false) { + handleBroadCastThreadPool_.Start(THREAD_NUM); } +FileAccessService::~FileAccessService() +{ + handleBroadCastThreadPool_.Stop(); +} + + void FileAccessService::OnStart() { UserAccessTracer trace; trace.Start("OnStart"); - sptr service = FileAccessService::GetInstance(); - if (service == nullptr) { - HILOG_ERROR("service is nullptr"); - return; - } - service->Init(); - if (!Publish(service)) { + Init(); + if (!Publish(this)) { HILOG_ERROR("OnStart register to system ability manager failed"); return; } @@ -724,6 +731,7 @@ void FileAccessService::InitTimer() HILOG_ERROR("UnloadSA, GetSystemAbilityManager is null."); return; } + UnRegisterBundleBroadcast(); int32_t result = saManager->UnloadSystemAbility(FILE_ACCESS_SERVICE_ID); if (result != ERR_OK) { HILOG_ERROR("UnloadSA, UnloadSystemAbility result: %{public}d", result); @@ -907,5 +915,56 @@ void FileAccessService::AppDeathRecipient::OnRemoteDied(const wptrRemoveAppProxy(remoteBroker); } +void FileAccessService::OnStart(const SystemAbilityOnDemandReason &startReason) +{ + HILOG_INFO("FileAccessService::OnStart"); + AddSystemAbilityListener(COMMON_EVENT_SERVICE_ID); + if (startReason.HasExtraData()) { + auto task = [this, startReason]() { + BundleObserver::HandleBundleBroadcast(); + }; + handleBroadCastThreadPool_.AddTask(task); + } + OnStart(); +} + +void FileAccessService::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId) +{ + HILOG_INFO("FileAccessService::OnAddSystemAbility Begin"); + if (systemAbilityId == COMMON_EVENT_SERVICE_ID) { + if (bundleObserver_ == nullptr) { + HILOG_ERROR("OnAddSystemAbility, bundleObserver is null, Will register bundle broadcast"); + RegisterBundleBroadcast(); + } + } +} + +void FileAccessService::OnRemoveSystemAbility(int32_t systemAbilityId, const std::string &deviceId) +{ + HILOG_INFO("FileAccessService::OnRemoveSystemAbility"); +} + + +void FileAccessService::RegisterBundleBroadcast() +{ + HILOG_INFO("FileAccessService::RegisterBundleBroadcast Begin"); + EventFwk::MatchingSkills matchingSkills; + matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED); + EventFwk::CommonEventSubscribeInfo subscriberInfo(matchingSkills); + bundleObserver_ = std::make_shared(subscriberInfo); + EventFwk::CommonEventManager::NewSubscribeCommonEvent(bundleObserver_); + HILOG_INFO("FileAccessService::RegisterBundleBroadcast End"); +} + +void FileAccessService::UnRegisterBundleBroadcast() +{ + HILOG_INFO("FileAccessService::UnRegisterBundleBroadcast Begin"); + if (bundleObserver_ == nullptr) { + HILOG_ERROR("UnRegisterBundleBroadcast error, bundleObserver is null"); + return; + } + int32_t ret = EventFwk::CommonEventManager::NewUnSubscribeCommonEventSync(bundleObserver_); + HILOG_INFO("FileAccessService::UnRegisterBundleBroadcast End. ret = %{public}d", ret); +} } // namespace FileAccessFwk } // namespace OHOS diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 1e41b55e..b9d895dc 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -371,6 +371,70 @@ ohos_unittest("urie_test") { defines = [ "private=public" ] } +ohos_unittest("file_access_service_test") { + branch_protector_ret = "pac_ret" + sanitize = { + integer_overflow = true + cfi = true + cfi_cross_dso = true + debug = false + } + module_out_path = "user_file_service/user_file_service" + + sources = [ + "file_access_service_test.cpp", + "bundle_observer_test.cpp", + "mock/file_access_service_mock.h", + ] + + include_dirs = [ + "${user_file_service_path}/interfaces/inner_api/file_access/include", + "${user_file_service_path}/services/native/file_access_service/include", + "mock", + ] + + configs = [ "//build/config/compiler:exceptions" ] + + deps = [ + "${user_file_service_path}/interfaces/inner_api/file_access:file_access_ext_base_include", + "${user_file_service_path}/interfaces/inner_api/file_access:file_access_extension_ability_kit", + "${user_file_service_path}/services:file_access_service", + "${user_file_service_path}/services:file_access_service_base_source", + ] + + external_deps = [ + "ability_base:want", + "ability_base:zuri", + "ability_runtime:ability_context_native", + "ability_runtime:ability_manager", + "ability_runtime:abilitykit_native", + "ability_runtime:app_context", + "ability_runtime:app_manager", + "ability_runtime:runtime", + "ability_runtime:wantagent_innerkits", + "access_token:libaccesstoken_sdk", + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "bundle_framework:appexecfwk_core", + "cJSON:cjson_static", + "c_utils:utils", + "googletest:gmock_main", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_core", + "ipc:rpc", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + "selinux_adapter:librestorecon", + ] + + defines = [ + "private=public", + "protected=public", + + ] +} + group("user_file_service_unit_test") { testonly = true @@ -380,6 +444,7 @@ group("user_file_service_unit_test") { ":external_file_access_management_test", ":external_file_access_notify_test", ":file_access_ext_stub_impl_test", + ":file_access_service_test", ":js_file_access_ext_ability_test", ":urie_test", ] diff --git a/test/unittest/bundle_observer_test.cpp b/test/unittest/bundle_observer_test.cpp new file mode 100644 index 00000000..37e61bd6 --- /dev/null +++ b/test/unittest/bundle_observer_test.cpp @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2024-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "bundle_observer.h" +#include "common_event_data.h" +#include "common_event_support.h" +#include "want.h" +#include "system_ability_ondemand_reason.h" +#include "iservice_registry.h" +#include "if_system_ability_manager.h" + +namespace OHOS { +namespace FileAccessFwk { +using namespace testing; +using namespace testing::ext; + +class ISystemAbilityManagerMockTest : public ISystemAbilityManager { +public: + MOCK_METHOD0(AsObject, sptr()); + MOCK_METHOD1(ListSystemAbilities, std::vector(unsigned int dumpFlags)); + MOCK_METHOD1(GetSystemAbility, sptr(int32_t systemAbilityId)); + MOCK_METHOD1(CheckSystemAbility, sptr(int32_t systemAbilityId)); + MOCK_METHOD1(RemoveSystemAbility, int32_t(int32_t systemAbilityId)); + MOCK_METHOD2(SubscribeSystemAbility, int32_t(int32_t systemAbilityId, + const sptr& listener)); + MOCK_METHOD2(UnSubscribeSystemAbility, int32_t(int32_t systemAbilityId, + const sptr& listener)); + MOCK_METHOD2(GetSystemAbility, sptr(int32_t systemAbilityId, const std::string& deviceId)); + MOCK_METHOD2(CheckSystemAbility, sptr(int32_t systemAbilityId, const std::string& deviceId)); + MOCK_METHOD2(AddOnDemandSystemAbilityInfo, int32_t(int32_t systemAbilityId, + const std::u16string& localAbilityManagerName)); + MOCK_METHOD2(CheckSystemAbility, sptr(int32_t systemAbilityId, bool& isExist)); + MOCK_METHOD3(AddSystemAbility, int32_t(int32_t systemAbilityId, const sptr& ability, + const SAExtraProp& extraProp)); + MOCK_METHOD2(AddSystemProcess, int32_t(const std::u16string& procName, const sptr& procObject)); + MOCK_METHOD2(LoadSystemAbility, sptr(int32_t systemAbilityId, int32_t timeout)); + MOCK_METHOD2(LoadSystemAbility, int32_t(int32_t systemAbilityId, const sptr& callback)); + MOCK_METHOD3(LoadSystemAbility, int32_t(int32_t systemAbilityId, const std::string& deviceId, + const sptr& callback)); + MOCK_METHOD1(UnloadSystemAbility, int32_t(int32_t systemAbilityId)); + MOCK_METHOD1(CancelUnloadSystemAbility, int32_t(int32_t systemAbilityId)); + MOCK_METHOD0(UnloadAllIdleSystemAbility, int32_t()); + MOCK_METHOD2(GetSystemProcessInfo, int32_t(int32_t systemAbilityId, SystemProcessInfo& systemProcessInfo)); + MOCK_METHOD1(GetRunningSystemProcess, int32_t(std::list& systemProcessInfos)); + MOCK_METHOD1(SubscribeSystemProcess, int32_t(const sptr& listener)); + MOCK_METHOD4(SendStrategy, int32_t(int32_t type, std::vector& systemAbilityIds, + int32_t level, std::string& action)); + MOCK_METHOD1(UnSubscribeSystemProcess, int32_t(const sptr& listener)); + MOCK_METHOD2(GetOnDemandReasonExtraData, int32_t(int64_t extraDataId, MessageParcel& extraDataParcel)); + MOCK_METHOD3(GetOnDemandPolicy, int32_t(int32_t systemAbilityId, OnDemandPolicyType type, + std::vector& abilityOnDemandEvents)); + MOCK_METHOD3(UpdateOnDemandPolicy, int32_t(int32_t systemAbilityId, OnDemandPolicyType type, + const std::vector& abilityOnDemandEvents)); + MOCK_METHOD1(GetOnDemandSystemAbilityIds, int32_t(std::vector& systemAbilityIds)); + MOCK_METHOD2(GetExtensionSaIds, int32_t(const std::string& extension, std::vector &saIds)); + MOCK_METHOD2(GetExtensionRunningSaList, int32_t(const std::string& extension, + std::vector>& saList)); + MOCK_METHOD2(GetRunningSaExtensionInfoList, int32_t(const std::string& extension, + std::vector& infoList)); + MOCK_METHOD3(GetCommonEventExtraDataIdlist, int32_t(int32_t systemAbilityId, + std::vector& extraDataIdList, const std::string& eventName)); +}; + +class BundleObserverTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; + +void BundleObserverTest::SetUpTestCase() +{ +} + +void BundleObserverTest::TearDownTestCase() +{ +} + +void BundleObserverTest::SetUp() +{ +} + +void BundleObserverTest::TearDown() +{ +} + +/** + * @tc.name: BundleObserverConstructorTest + * @tc.desc: Test BundleObserver constructor + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverConstructorTest, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverConstructorTest start"; + EventFwk::CommonEventSubscribeInfo subscribeInfo; + BundleObserver observer(subscribeInfo); + GTEST_LOG_(INFO) << "BundleObserverConstructorTest end"; +} + +/** + * @tc.name: BundleObserverHandleBundleBroadcastTest001 + * @tc.desc: Test HandleBundleBroadcast when SystemAbilityManager is null + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverHandleBundleBroadcastTest001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverHandleBundleBroadcastTest001 start"; + int32_t result = BundleObserver::HandleBundleBroadcast(); + EXPECT_EQ(result, ERR_INVALID_VALUE); + GTEST_LOG_(INFO) << "BundleObserverHandleBundleBroadcastTest001 end"; +} + +/** + * @tc.name: BundleObserverHandleBundleBroadcastTest002 + * @tc.desc: Test HandleBundleBroadcast when GetCommonEventExtraDataIdList fails + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverHandleBundleBroadcastTest002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverHandleBundleBroadcastTest002 start"; + sptr saMgrMock = new ISystemAbilityManagerMockTest(); + EXPECT_CALL(*saMgrMock, GetCommonEventExtraDataIdlist(testing::_, testing::_, testing::_)) + .WillOnce(testing::Return(-1)); + int32_t result = BundleObserver::HandleBundleBroadcast(); + EXPECT_EQ(result, -1); + GTEST_LOG_(INFO) << "BundleObserverHandleBundleBroadcastTest002 end"; +} + +/** + * @tc.name: BundleObserverClearSyncFolderTest001 + * @tc.desc: Test ClearSyncFolder with empty sync folders + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverClearSyncFolderTest001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverClearSyncFolderTest001 start"; + std::string bundleName = "test.bundle"; + int32_t userId = 100; + int32_t appIndex = 0; + int32_t result = BundleObserver::ClearSyncFolder(bundleName, userId, appIndex); + EXPECT_EQ(result, ERR_INVALID_VALUE); + GTEST_LOG_(INFO) << "BundleObserverClearSyncFolderTest001 end"; +} + +/** + * @tc.name: BundleObserverClearSyncFolderTest002 + * @tc.desc: Test ClearSyncFolder with non-empty sync folders + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverClearSyncFolderTest002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverClearSyncFolderTest002 start"; + std::string bundleName = "test.bundle"; + int32_t userId = 100; + int32_t appIndex = 0; + int32_t result = BundleObserver::ClearSyncFolder(bundleName, userId, appIndex); + EXPECT_EQ(result, ERR_INVALID_VALUE); + GTEST_LOG_(INFO) << "BundleObserverClearSyncFolderTest002 end"; +} + +/** + * @tc.name: BundleObserverClearSyncFolderTest003 + * @tc.desc: Test ClearSyncFolder with non-empty sync folders and successful deletion + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverClearSyncFolderTest003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverClearSyncFolderTest003 start"; + // This test would require mocking SynchronousRootManager and NotifyWorkerService + // Since these are not easily mockable in the current setup, we'll focus on the logic flow + std::string bundleName = "test.bundle"; + int32_t userId = 100; + int32_t appIndex = 0; + int32_t result = BundleObserver::ClearSyncFolder(bundleName, userId, appIndex); + // In real implementation, this would depend on the mocked behavior of SynchronousRootManager + // For now, we expect it to return ERR_INVALID_VALUE because we can't easily mock the dependencies + EXPECT_EQ(result, ERR_INVALID_VALUE); + GTEST_LOG_(INFO) << "BundleObserverClearSyncFolderTest003 end"; +} + +/** + * @tc.name: BundleObserverOnReceiveEventTest001 + * @tc.desc: Test OnReceiveEvent with package removed event + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverOnReceiveEventTest001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverOnReceiveEventTest001 start"; + EventFwk::CommonEventSubscribeInfo subscribeInfo; + BundleObserver observer(subscribeInfo); + + EventFwk::CommonEventData data; + OHOS::AAFwk::Want want; + want.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED); + + std::string bundleName = "com.example.test"; + want.SetParam("userId", 100); + want.SetParam("bundleName", bundleName); + want.SetParam("appIndex", 0); + data.SetWant(want); + observer.OnReceiveEvent(data); + GTEST_LOG_(INFO) << "BundleObserverOnReceiveEventTest001 end"; +} + +/** + * @tc.name: BundleObserverOnReceiveEventTest002 + * @tc.desc: Test OnReceiveEvent with other event + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverOnReceiveEventTest002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverOnReceiveEventTest002 start"; + EventFwk::CommonEventSubscribeInfo subscribeInfo; + BundleObserver observer(subscribeInfo); + + EventFwk::CommonEventData data; + OHOS::AAFwk::Want want; + want.SetAction("other_event"); + data.SetWant(want); + + observer.OnReceiveEvent(data); + GTEST_LOG_(INFO) << "BundleObserverOnReceiveEventTest002 end"; +} + +/** + * @tc.name: BundleObserverGetValueByKeyTest001 + * @tc.desc: Test GetValueByKey with existing key + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverGetValueByKeyTest001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverGetValueByKeyTest001 start"; + std::map testMap; + testMap["key1"] = "value1"; + testMap["key2"] = "value2"; + + std::string result = BundleObserver::GetValueByKey(testMap, "key1"); + EXPECT_EQ(result, "value1"); + GTEST_LOG_(INFO) << "BundleObserverGetValueByKeyTest001 end"; +} + +/** + * @tc.name: BundleObserverGetValueByKeyTest002 + * @tc.desc: Test GetValueByKey with non-existing key + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverGetValueByKeyTest002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverGetValueByKeyTest002 start"; + std::map testMap; + testMap["key1"] = "value1"; + testMap["key2"] = "value2"; + + std::string result = BundleObserver::GetValueByKey(testMap, "key3"); + EXPECT_EQ(result, ""); + GTEST_LOG_(INFO) << "BundleObserverGetValueByKeyTest002 end"; +} + +/** + * @tc.name: BundleObserverGetNumberFromStringTest001 + * @tc.desc: Test GetNumberFromString with valid string + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverGetNumberFromStringTest001, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverGetNumberFromStringTest001 start"; + std::string testStr = "123"; + int32_t defaultValue = 0; + + int32_t result = BundleObserver::GetNumberFromString(testStr, defaultValue); + EXPECT_EQ(result, 123); + GTEST_LOG_(INFO) << "BundleObserverGetNumberFromStringTest001 end"; +} + +/** + * @tc.name: BundleObserverGetNumberFromStringTest002 + * @tc.desc: Test GetNumberFromString with empty string + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverGetNumberFromStringTest002, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverGetNumberFromStringTest002 start"; + std::string testStr = ""; + int32_t defaultValue = 100; + + int32_t result = BundleObserver::GetNumberFromString(testStr, defaultValue); + EXPECT_EQ(result, 100); + GTEST_LOG_(INFO) << "BundleObserverGetNumberFromStringTest002 end"; +} + +/** + * @tc.name: BundleObserverGetNumberFromStringTest003 + * @tc.desc: Test GetNumberFromString with invalid string + * @tc.type: FUNC + */ +HWTEST_F(BundleObserverTest, BundleObserverGetNumberFromStringTest003, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BundleObserverGetNumberFromStringTest003 start"; + std::string testStr = "abc"; + int32_t defaultValue = 100; + + int32_t result = BundleObserver::GetNumberFromString(testStr, defaultValue); + EXPECT_EQ(result, 0); + GTEST_LOG_(INFO) << "BundleObserverGetNumberFromStringTest003 end"; +} +} // namespace FileAccessFwk +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/file_access_service_test.cpp b/test/unittest/file_access_service_test.cpp new file mode 100644 index 00000000..f5299c9c --- /dev/null +++ b/test/unittest/file_access_service_test.cpp @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2024-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "file_access_service.h" +#include "file_access_service_mock.h" +#include "file_access_ext_connection.h" +#include "file_access_framework_errno.h" +#include "uri.h" +#include "want.h" +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" +#include "system_ability_definition.h" +#include "ipc_skeleton.h" +#include "message_parcel.h" +#include "message_option.h" +#include "iremote_object.h" +#include "ifile_access_ext_base.h" +#include "file_access_extension_info.h" + +namespace OHOS { +namespace FileAccessFwk { +using namespace testing; +using namespace testing::ext; + +class FileAccessServiceTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; + + static void SetNativeToken(); + static sptr service_; + static std::shared_ptr serviceMock_; +}; + +sptr FileAccessServiceTest::service_ = nullptr; +std::shared_ptr FileAccessServiceTest::serviceMock_ = nullptr; + +void FileAccessServiceTest::SetUpTestCase() +{ + SetNativeToken(); + service_ = FileAccessService::GetInstance(); + ASSERT_NE(service_, nullptr); + serviceMock_ = std::make_shared(); +} + +void FileAccessServiceTest::TearDownTestCase() +{ + service_ = nullptr; + serviceMock_ = nullptr; +} + +void FileAccessServiceTest::SetUp() +{ +} + +void FileAccessServiceTest::TearDown() +{ +} + +void FileAccessServiceTest::SetNativeToken() +{ + uint64_t tokenId; + const char *perms[] = { + "ohos.permission.FILE_ACCESS_MANAGER", + "ohos.permission.GET_BUNDLE_INFO_PRIVILEGED", + "ohos.permission.CONNECT_FILE_ACCESS_EXTENSION" + }; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, + .permsNum = 3, + .aclsNum = 0, + .dcaps = nullptr, + .perms = perms, + .acls = nullptr, + .processName = "file_access_service_test", + .aplStr = "system_basic", + }; + tokenId = GetAccessTokenId(&infoInstance); + SetSelfTokenID(tokenId); + Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo(); +} + +/** + * @tc.name: GetInstanceTest + * @tc.desc: Test get instance of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, GetInstanceTest, TestSize.Level1) +{ + auto instance = FileAccessService::GetInstance(); + EXPECT_NE(instance, nullptr); +} + +/** + * @tc.name: OnStartTest + * @tc.desc: Test OnStart method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, OnStartTest, TestSize.Level1) +{ + service_->OnStart(); + EXPECT_TRUE(service_->IsServiceReady()); +} + +/** + * @tc.name: OnStopTest + * @tc.desc: Test OnStop method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, OnStopTest, TestSize.Level1) +{ + service_->OnStop(); + // Note: This test just verifies the method can be called without crashing + // Reset the service state after test + service_->OnStart(); +} + +/** + * @tc.name: CheckCallingPermissionTest + * @tc.desc: Test CheckCallingPermission method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, CheckCallingPermissionTest, TestSize.Level1) +{ + std::string permission = "ohos.permission.FILE_ACCESS_MANAGER"; + bool result = service_->CheckCallingPermission(permission); + EXPECT_TRUE(result); +} + +/** + * @tc.name: IsServiceReadyTest + * @tc.desc: Test IsServiceReady method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, IsServiceReadyTest, TestSize.Level1) +{ + service_->OnStart(); + bool ready = service_->IsServiceReady(); + EXPECT_TRUE(ready); +} + +/** + * @tc.name: ConnectFileExtAbilityTest + * @tc.desc: Test ConnectFileExtAbility method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, ConnectFileExtAbilityTest, TestSize.Level1) +{ + AAFwk::Want want; + sptr connection = nullptr; + int32_t result = service_->ConnectFileExtAbility(want, connection); + EXPECT_EQ(result, ERR_OK); +} + +/** + * @tc.name: DisConnectFileExtAbilityTest + * @tc.desc: Test DisConnectFileExtAbility method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, DisConnectFileExtAbilityTest, TestSize.Level1) +{ + sptr connection = nullptr; + int32_t result = service_->DisConnectFileExtAbility(connection); + EXPECT_EQ(result, ERR_OK); +} + +/** + * @tc.name: RegisterNotifyTest + * @tc.desc: Test RegisterNotify method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, RegisterNotifyTest, TestSize.Level1) +{ + Uri uri("file://com.example.data/storage/Users"); + bool notifyForDescendants = true; + sptr observer = nullptr; + ConnectExtensionInfo info; + int32_t result = service_->RegisterNotify(uri, notifyForDescendants, observer, info); + EXPECT_EQ(result, E_PERMISSION); +} + +/** + * @tc.name: UnregisterNotifyTest + * @tc.desc: Test UnregisterNotify method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, UnregisterNotifyTest, TestSize.Level1) +{ + Uri uri("file://com.example.data/storage/Users"); + sptr observer = nullptr; + ConnectExtensionInfo info; + int32_t result = service_->UnregisterNotify(uri, observer, info); + EXPECT_EQ(result, E_PERMISSION); +} + +/** + * @tc.name: UnregisterNotifyNoObserverTest + * @tc.desc: Test UnregisterNotifyNoObserver method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, UnregisterNotifyNoObserverTest, TestSize.Level1) +{ + Uri uri("file://com.example.data/storage/Users"); + ConnectExtensionInfo info; + int32_t result = service_->UnregisterNotifyNoObserver(uri, info); + EXPECT_EQ(result, E_PERMISSION); +} + +/** + * @tc.name: OnChangeTest + * @tc.desc: Test OnChange method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, OnChangeTest, TestSize.Level1) +{ + Uri uri("file://com.example.data/storage/Users"); + NotifyType notifyType = NotifyType::NOTIFY_INSERT; + int32_t result = service_->OnChange(uri, notifyType); + EXPECT_EQ(result, E_PERMISSION); +} + +/** + * @tc.name: GetExtensionProxyTest + * @tc.desc: Test GetExtensionProxy method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, GetExtensionProxyTest, TestSize.Level1) +{ + ConnectExtensionInfo info; + sptr extensionProxy = nullptr; + int32_t result = service_->GetExtensionProxy(info, extensionProxy); + EXPECT_EQ(result, E_PERMISSION); +} + +/** + * @tc.name: IsUnusedTest + * @tc.desc: Test IsUnused method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, IsUnusedTest, TestSize.Level1) +{ + bool result = service_->IsUnused(); + // This will depend on the current state, but shouldn't crash + EXPECT_FALSE(result); // Since we have active connections +} + +/** + * @tc.name: FindExtProxyByBundleNameTest + * @tc.desc: Test FindExtProxyByBundleName method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, FindExtProxyByBundleNameTest, TestSize.Level1) +{ + std::string bundleName = "com.example.data"; + sptr result = service_->FindExtProxyByBundleName(bundleName); + // Should return nullptr since we haven't registered any extensions + EXPECT_EQ(result, nullptr); +} + +/** + * @tc.name: AddExtProxyInfoTest + * @tc.desc: Test AddExtProxyInfo method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, AddExtProxyInfoTest, TestSize.Level1) +{ + std::string bundleName = "com.test.bundle"; + sptr extProxy = nullptr; + // This should not crash + service_->AddExtProxyInfo(bundleName, extProxy); + // Verify the proxy was added + sptr result = service_->FindExtProxyByBundleName(bundleName); + EXPECT_EQ(result, extProxy); +} + +/** + * @tc.name: OnStartWithReasonTest + * @tc.desc: Test OnStart with SystemAbilityOnDemandReason method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, OnStartWithReasonTest, TestSize.Level1) +{ + SystemAbilityOnDemandReason startReason; + // This test just verifies the method can be called without crashing + // In a real scenario, this would trigger HandleBundleBroadcast in a separate thread + service_->OnStart(startReason); +} + +/** + * @tc.name: OnAddSystemAbilityTest + * @tc.desc: Test OnAddSystemAbility method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, OnAddSystemAbilityTest, TestSize.Level1) +{ + // Test with COMMON_EVENT_SERVICE_ID + service_->OnAddSystemAbility(COMMON_EVENT_SERVICE_ID, ""); + // Should register bundle broadcast + EXPECT_NE(service_->bundleObserver_, nullptr); +} + +/** + * @tc.name: OnRemoveSystemAbilityTest + * @tc.desc: Test OnRemoveSystemAbility method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, OnRemoveSystemAbilityTest, TestSize.Level1) +{ + // Test with COMMON_EVENT_SERVICE_ID when bundleObserver_ is not null + service_->OnRemoveSystemAbility(COMMON_EVENT_SERVICE_ID, ""); +} + +/** + * @tc.name: RegisterBundleBroadcastTest + * @tc.desc: Test RegisterBundleBroadcast method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, RegisterBundleBroadcastTest, TestSize.Level1) +{ + // Save current bundleObserver_ + auto oldObserver = service_->bundleObserver_; + + // Register new bundle broadcast + service_->RegisterBundleBroadcast(); + + // Should have a bundle observer now + EXPECT_NE(service_->bundleObserver_, nullptr); + + // Restore original observer + service_->bundleObserver_ = oldObserver; +} + +/** + * @tc.name: UnRegisterBundleBroadcastTest + * @tc.desc: Test UnRegisterBundleBroadcast method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, UnRegisterBundleBroadcastTest, TestSize.Level1) +{ + // Save current bundleObserver_ + auto oldObserver = service_->bundleObserver_; + + // Create a mock bundle observer for testing + EventFwk::MatchingSkills matchingSkills; + matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED); + EventFwk::CommonEventSubscribeInfo subscriberInfo(matchingSkills); + auto testObserver = std::make_shared(subscriberInfo); + service_->bundleObserver_ = testObserver; + + // Unregister bundle broadcast + service_->UnRegisterBundleBroadcast(); + + // Restore original observer + service_->bundleObserver_ = oldObserver; +} + +/** + * @tc.name: GetInstanceDoubleCallTest + * @tc.desc: Test double call to GetInstance method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, GetInstanceDoubleCallTest, TestSize.Level1) +{ + auto instance1 = FileAccessService::GetInstance(); + auto instance2 = FileAccessService::GetInstance(); + EXPECT_EQ(instance1, instance2); +} + +/** + * @tc.name: InitTest + * @tc.desc: Test Init method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, InitTest, TestSize.Level1) +{ + // Call Init method + service_->Init(); + + // Check that death recipients are created + EXPECT_NE(service_->extensionDeathRecipient_, nullptr); + EXPECT_NE(service_->observerDeathRecipient_, nullptr); + EXPECT_NE(service_->appDeathRecipient_, nullptr); +} + +/** + * @tc.name: DumpTest + * @tc.desc: Test Dump method of FileAccessService + * @tc.type: FUNC + */ +HWTEST_F(FileAccessServiceTest, DumpTest, TestSize.Level1) +{ + int32_t fd = 1; + std::vector args; + int32_t result = service_->Dump(fd, args); + EXPECT_EQ(result, ERR_OK); +} + +} // namespace FileAccessFwk +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/mock/file_access_service_mock.cpp b/test/unittest/mock/file_access_service_mock.cpp new file mode 100644 index 00000000..d737f661 --- /dev/null +++ b/test/unittest/mock/file_access_service_mock.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "file_access_service_mock.h" +#include + +namespace OHOS { +namespace FileAccessFwk { + +} +} diff --git a/test/unittest/mock/file_access_service_mock.h b/test/unittest/mock/file_access_service_mock.h index 6e8f4492..6f5f76a3 100644 --- a/test/unittest/mock/file_access_service_mock.h +++ b/test/unittest/mock/file_access_service_mock.h @@ -17,6 +17,14 @@ #define FILE_ACCESS_SERVICE_MOCK_H #include "file_access_service_base_stub.h" +#include "file_access_service.h" +#include "uri.h" +#include "file_info.h" +#include "root_info.h" +#include "file_access_extension_info.h" +#include "want.h" +#include "iability_connection.h" +#include "ifile_access_ext_base.h" namespace OHOS { namespace FileAccessFwk { @@ -42,6 +50,15 @@ public: MOCK_METHOD2(ConnectFileExtAbility, int32_t(const AAFwk::Want &want, const sptr& connection)); MOCK_METHOD1(DisConnectFileExtAbility, int32_t(const sptr& connection)); + + // FileAccessService specific methods + MOCK_METHOD0(OnStart, void()); + MOCK_METHOD0(OnStop, void()); + MOCK_METHOD2(CheckCallingPermission, bool(const std::string &permission, int32_t tokenId)); + MOCK_METHOD0(IsServiceReady, bool()); + MOCK_METHOD3(RegisterUriObserver, int32_t(const Uri &uri, const sptr &observer, bool notifyForDescendants)); + MOCK_METHOD2(UnregisterUriObserver, int32_t(const Uri &uri, const sptr &observer)); + MOCK_METHOD1(UnregisterUriObserverWithoutObserver, int32_t(const Uri &uri)); }; } // namespace FileAccessFwk } // namespace OHOS -- Gitee