From 9c160b61fe9e0b464c1ad30d31eb094b9f0a1a33 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Wed, 13 Jan 2021 15:12:28 -0800 Subject: [PATCH 1/5] Refactor common implementation for health storage HAL. Create a new library, libhealth_storage_impl_common, that's useful for common health storage HAL implementation. Test: TH Change-Id: I07c51d0b9c2e2262bf327dc3deabc7b41c89355d --- health/storage/1.0/default/Android.bp | 1 + health/storage/1.0/default/Storage.cpp | 90 +------------ health/storage/impl_common/Android.bp | 47 +++++++ health/storage/impl_common/impl_common.cpp | 118 ++++++++++++++++++ .../include/health-storage-impl/common.h | 31 +++++ 5 files changed, 200 insertions(+), 87 deletions(-) create mode 100644 health/storage/impl_common/Android.bp create mode 100644 health/storage/impl_common/impl_common.cpp create mode 100644 health/storage/impl_common/include/health-storage-impl/common.h diff --git a/health/storage/1.0/default/Android.bp b/health/storage/1.0/default/Android.bp index 3156dfef1c..3834244cea 100644 --- a/health/storage/1.0/default/Android.bp +++ b/health/storage/1.0/default/Android.bp @@ -38,6 +38,7 @@ cc_binary { ], static_libs: [ + "libhealth_storage_impl_common", "libfstab", ], diff --git a/health/storage/1.0/default/Storage.cpp b/health/storage/1.0/default/Storage.cpp index 561deaaed6..02b6a3dbf0 100644 --- a/health/storage/1.0/default/Storage.cpp +++ b/health/storage/1.0/default/Storage.cpp @@ -18,11 +18,8 @@ #include -#include -#include #include -#include -#include +#include namespace android { namespace hardware { @@ -31,69 +28,9 @@ namespace storage { namespace V1_0 { namespace implementation { -using base::ReadFileToString; -using base::Timer; -using base::Trim; -using base::WriteStringToFd; -using base::WriteStringToFile; -using fs_mgr::Fstab; -using fs_mgr::ReadDefaultFstab; - -std::string getGarbageCollectPath() { - Fstab fstab; - ReadDefaultFstab(&fstab); - - for (const auto& entry : fstab) { - if (!entry.sysfs_path.empty()) { - return entry.sysfs_path + "/manual_gc"; - } - } - - return ""; -} - Return Storage::garbageCollect(uint64_t timeoutSeconds, const sp& cb) { - Result result = Result::SUCCESS; - std::string path = getGarbageCollectPath(); - - if (path.empty()) { - LOG(WARNING) << "Cannot find Dev GC path"; - result = Result::UNKNOWN_ERROR; - } else { - Timer timer; - LOG(INFO) << "Start Dev GC on " << path; - while (1) { - std::string require; - if (!ReadFileToString(path, &require)) { - PLOG(WARNING) << "Reading manual_gc failed in " << path; - result = Result::IO_ERROR; - break; - } - require = Trim(require); - if (require == "" || require == "off" || require == "disabled") { - LOG(DEBUG) << "No more to do Dev GC"; - break; - } - LOG(DEBUG) << "Trigger Dev GC on " << path; - if (!WriteStringToFile("1", path)) { - PLOG(WARNING) << "Start Dev GC failed on " << path; - result = Result::IO_ERROR; - break; - } - if (timer.duration() >= std::chrono::seconds(timeoutSeconds)) { - LOG(WARNING) << "Dev GC timeout"; - // Timeout is not treated as an error. Try next time. - break; - } - sleep(2); - } - LOG(INFO) << "Stop Dev GC on " << path; - if (!WriteStringToFile("0", path)) { - PLOG(WARNING) << "Stop Dev GC failed on " << path; - result = Result::IO_ERROR; - } - } + Result result = GarbageCollect(timeoutSeconds); if (cb != nullptr) { auto ret = cb->onFinish(result); @@ -110,28 +47,7 @@ Return Storage::debug(const hidl_handle& handle, const hidl_vecdata[0]; - std::stringstream output; - - std::string path = getGarbageCollectPath(); - if (path.empty()) { - output << "Cannot find Dev GC path"; - } else { - std::string require; - - if (ReadFileToString(path, &require)) { - output << path << ":" << require << std::endl; - } - - if (WriteStringToFile("0", path)) { - output << "stop success" << std::endl; - } - } - - if (!WriteStringToFd(output.str(), fd)) { - PLOG(WARNING) << "debug: cannot write to fd"; - } - - fsync(fd); + DebugDump(fd); return Void(); } diff --git a/health/storage/impl_common/Android.bp b/health/storage/impl_common/Android.bp new file mode 100644 index 0000000000..e1149c0cb7 --- /dev/null +++ b/health/storage/impl_common/Android.bp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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. + */ + +// Common implementation between HIDL and AIDL HAL. +cc_library_static { + name: "libhealth_storage_impl_common", + vendor: true, + srcs: [ + "impl_common.cpp", + ], + export_include_dirs: [ + "include", + ], + + cflags: [ + "-Wall", + "-Werror", + ], + + shared_libs: [ + "libbase", + "libhidlbase", + "liblog", + "android.hardware.health.storage@1.0", + ], + + static_libs: [ + "libfstab", + ], + + export_shared_lib_headers: [ + "android.hardware.health.storage@1.0", + ], +} diff --git a/health/storage/impl_common/impl_common.cpp b/health/storage/impl_common/impl_common.cpp new file mode 100644 index 0000000000..6e753d4655 --- /dev/null +++ b/health/storage/impl_common/impl_common.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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 +#include +#include + +using ::android::base::ReadFileToString; +using ::android::base::Timer; +using ::android::base::Trim; +using ::android::base::WriteStringToFd; +using ::android::base::WriteStringToFile; +using ::android::fs_mgr::Fstab; +using ::android::fs_mgr::ReadDefaultFstab; +using ::android::hardware::health::storage::V1_0::Result; + +namespace android::hardware::health::storage { + +static std::string GetGarbageCollectPath() { + Fstab fstab; + ReadDefaultFstab(&fstab); + + for (const auto& entry : fstab) { + if (!entry.sysfs_path.empty()) { + return entry.sysfs_path + "/manual_gc"; + } + } + + return ""; +} + +Result GarbageCollect(uint64_t timeout_seconds) { + std::string path = GetGarbageCollectPath(); + + if (path.empty()) { + LOG(WARNING) << "Cannot find Dev GC path"; + return Result::UNKNOWN_ERROR; + } + + Result result = Result::SUCCESS; + Timer timer; + LOG(INFO) << "Start Dev GC on " << path; + while (1) { + std::string require; + if (!ReadFileToString(path, &require)) { + PLOG(WARNING) << "Reading manual_gc failed in " << path; + result = Result::IO_ERROR; + break; + } + require = Trim(require); + if (require == "" || require == "off" || require == "disabled") { + LOG(DEBUG) << "No more to do Dev GC"; + break; + } + LOG(DEBUG) << "Trigger Dev GC on " << path; + if (!WriteStringToFile("1", path)) { + PLOG(WARNING) << "Start Dev GC failed on " << path; + result = Result::IO_ERROR; + break; + } + if (timer.duration() >= std::chrono::seconds(timeout_seconds)) { + LOG(WARNING) << "Dev GC timeout"; + // Timeout is not treated as an error. Try next time. + break; + } + sleep(2); + } + LOG(INFO) << "Stop Dev GC on " << path; + if (!WriteStringToFile("0", path)) { + PLOG(WARNING) << "Stop Dev GC failed on " << path; + result = Result::IO_ERROR; + } + + return result; +} + +void DebugDump(int fd) { + std::stringstream output; + + std::string path = GetGarbageCollectPath(); + if (path.empty()) { + output << "Cannot find Dev GC path"; + } else { + std::string require; + + if (ReadFileToString(path, &require)) { + output << path << ":" << require << std::endl; + } + + if (WriteStringToFile("0", path)) { + output << "stop success" << std::endl; + } + } + + if (!WriteStringToFd(output.str(), fd)) { + PLOG(WARNING) << "debug: cannot write to fd"; + } + + fsync(fd); +} + +} // namespace android::hardware::health::storage diff --git a/health/storage/impl_common/include/health-storage-impl/common.h b/health/storage/impl_common/include/health-storage-impl/common.h new file mode 100644 index 0000000000..c84a6a94a4 --- /dev/null +++ b/health/storage/impl_common/include/health-storage-impl/common.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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. + */ + +#pragma once + +#include +#include + +namespace android::hardware::health::storage { + +// Run debug on fd +void DebugDump(int fd); + +// Run garbage collection on GetGarbageCollectPath(). Blocks until garbage +// collect finishes or |timeout_seconds| has reached. +V1_0::Result GarbageCollect(uint64_t timeout_seconds); + +} // namespace android::hardware::health::storage From c78079b333b73d0997b94ee6c6fff5f5201cd732 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Wed, 13 Jan 2021 14:18:15 -0800 Subject: [PATCH 2/5] Add health.storage AIDL HAL Test: TH Bug: 177470478 Change-Id: Ib982fb4e98403edcbe23034569373a7777b139f1 --- .../compatibility_matrix.current.xml | 8 +++ health/storage/aidl/Android.bp | 33 +++++++++++++ .../storage/IGarbageCollectCallback.aidl | 23 +++++++++ .../hardware/health/storage/IStorage.aidl | 23 +++++++++ .../hardware/health/storage/Result.aidl | 25 ++++++++++ .../storage/IGarbageCollectCallback.aidl | 34 +++++++++++++ .../hardware/health/storage/IStorage.aidl | 49 +++++++++++++++++++ .../hardware/health/storage/Result.aidl | 37 ++++++++++++++ 8 files changed, 232 insertions(+) create mode 100644 health/storage/aidl/Android.bp create mode 100644 health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/IGarbageCollectCallback.aidl create mode 100644 health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/IStorage.aidl create mode 100644 health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/Result.aidl create mode 100644 health/storage/aidl/android/hardware/health/storage/IGarbageCollectCallback.aidl create mode 100644 health/storage/aidl/android/hardware/health/storage/IStorage.aidl create mode 100644 health/storage/aidl/android/hardware/health/storage/Result.aidl diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index 451eff4ef8..b91450be37 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -258,6 +258,14 @@ default + + android.hardware.health.storage + 1 + + IStorage + default + + android.hardware.identity diff --git a/health/storage/aidl/Android.bp b/health/storage/aidl/Android.bp new file mode 100644 index 0000000000..c39a46d48e --- /dev/null +++ b/health/storage/aidl/Android.bp @@ -0,0 +1,33 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// 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. + +aidl_interface { + name: "android.hardware.health.storage", + vendor_available: true, + srcs: ["android/hardware/health/storage/*.aidl"], + stability: "vintf", + backend: { + cpp: { + enabled: false, + }, + java: { + enabled: false, + }, + ndk: { + vndk: { + enabled: true, + }, + }, + }, +} diff --git a/health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/IGarbageCollectCallback.aidl b/health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/IGarbageCollectCallback.aidl new file mode 100644 index 0000000000..0f382d7e6d --- /dev/null +++ b/health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/IGarbageCollectCallback.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.health.storage; +@VintfStability +interface IGarbageCollectCallback { + oneway void onFinish(in android.hardware.health.storage.Result result); +} diff --git a/health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/IStorage.aidl b/health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/IStorage.aidl new file mode 100644 index 0000000000..61f838addd --- /dev/null +++ b/health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/IStorage.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.health.storage; +@VintfStability +interface IStorage { + oneway void garbageCollect(in long timeoutSeconds, in android.hardware.health.storage.IGarbageCollectCallback callback); +} diff --git a/health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/Result.aidl b/health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/Result.aidl new file mode 100644 index 0000000000..a34580855b --- /dev/null +++ b/health/storage/aidl/aidl_api/android.hardware.health.storage/current/android/hardware/health/storage/Result.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.health.storage; +@Backing(type="int") @VintfStability +enum Result { + SUCCESS = 0, + IO_ERROR = 1, + UNKNOWN_ERROR = 2, +} diff --git a/health/storage/aidl/android/hardware/health/storage/IGarbageCollectCallback.aidl b/health/storage/aidl/android/hardware/health/storage/IGarbageCollectCallback.aidl new file mode 100644 index 0000000000..ccd1b44829 --- /dev/null +++ b/health/storage/aidl/android/hardware/health/storage/IGarbageCollectCallback.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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. + */ + +package android.hardware.health.storage; + +import android.hardware.health.storage.Result; + +/** + * Callback interface to IStorage.garbageCollect. + */ +@VintfStability +interface IGarbageCollectCallback { + /** + * When garbage collection has finished, the implementation must + * invoke this function to indicate the result of the garbage collection. + * + * @param out result Execution result. See documentation for Result for + * details. + */ + oneway void onFinish(in Result result); +} diff --git a/health/storage/aidl/android/hardware/health/storage/IStorage.aidl b/health/storage/aidl/android/hardware/health/storage/IStorage.aidl new file mode 100644 index 0000000000..78992a2bd8 --- /dev/null +++ b/health/storage/aidl/android/hardware/health/storage/IStorage.aidl @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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. + */ + +package android.hardware.health.storage; + +import android.hardware.health.storage.IGarbageCollectCallback; + +/** + * IStorage is an interface that provides operations on underlying storage + * devices, including flash memory. + */ +@VintfStability +interface IStorage { + /** + * Start garbage collection on the driver of storage devices. + * + * Garbage collection must be started at regular intervals when it is a good + * time for a longer-running cleanup tasks, roughly daily. + * + * When garbage collection finishes or encounters an error before the + * specified timeout, the implementation must call IGarbageCollect.finish + * immediately with appropriate result. + * + * If garbage collection does not finish within the specified timeout, + * the implementation must stop garbage collection, and must not call + * IGarbageCollect.finish. + * + * @param timeoutSeconds timeout in seconds. The implementation must + * return after the timeout is reached. + * + * @param callback callback interface. Callback must be null if the client + * does not need to receive any callbacks. + * + */ + oneway void garbageCollect(in long timeoutSeconds, in IGarbageCollectCallback callback); +} diff --git a/health/storage/aidl/android/hardware/health/storage/Result.aidl b/health/storage/aidl/android/hardware/health/storage/Result.aidl new file mode 100644 index 0000000000..73bb779f20 --- /dev/null +++ b/health/storage/aidl/android/hardware/health/storage/Result.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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. + */ + +package android.hardware.health.storage; + +/** + * Status values for HAL methods. + */ +@VintfStability +@Backing(type="int") +enum Result { + /** + * Execution of the method is successful. + */ + SUCCESS = 0, + /** + * An IO error is encountered when the HAL communicates with the device. + */ + IO_ERROR, + /** + * An unknown error is encountered. + */ + UNKNOWN_ERROR, +} From feed84d11dbf625869d3f57868dbb718881f8185 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Wed, 13 Jan 2021 14:56:51 -0800 Subject: [PATCH 3/5] Add default impl for health storage AIDL HAL Test: VTS Bug: 177470478 Change-Id: I23c32d51d40a681eb1d56b8f9fc59f1d4caaad2a --- health/storage/aidl/default/Android.bp | 53 ++++++++++++++++++ health/storage/aidl/default/Storage.cpp | 54 +++++++++++++++++++ health/storage/aidl/default/Storage.h | 30 +++++++++++ .../aidl/default/health-storage-default.rc | 7 +++ .../aidl/default/health-storage-default.xml | 7 +++ health/storage/aidl/default/main.cpp | 37 +++++++++++++ 6 files changed, 188 insertions(+) create mode 100644 health/storage/aidl/default/Android.bp create mode 100644 health/storage/aidl/default/Storage.cpp create mode 100644 health/storage/aidl/default/Storage.h create mode 100644 health/storage/aidl/default/health-storage-default.rc create mode 100644 health/storage/aidl/default/health-storage-default.xml create mode 100644 health/storage/aidl/default/main.cpp diff --git a/health/storage/aidl/default/Android.bp b/health/storage/aidl/default/Android.bp new file mode 100644 index 0000000000..68a8ee267f --- /dev/null +++ b/health/storage/aidl/default/Android.bp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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. + */ + +cc_defaults { + name: "libhealth_storage_impl_defaults", + vendor: true, + shared_libs: [ + "libbase", + "libbinder_ndk", + "android.hardware.health.storage-unstable-ndk_platform", + ], + static_libs: [ + "libfstab", + "libhealth_storage_impl_common", + ], +} + +cc_library_static { + name: "libhealth_storage_default_impl", + defaults: ["libhealth_storage_impl_defaults"], + srcs: [ + "Storage.cpp", + ], + visibility: [ + ":__subpackages__", + "//hardware/interfaces/tests/extension/health/storage:__subpackages__", + ], +} + +cc_binary { + name: "android.hardware.health.storage-service.default", + defaults: ["libhealth_storage_impl_defaults"], + relative_install_path: "hw", + init_rc: ["health-storage-default.rc"], + vintf_fragments: ["health-storage-default.xml"], + srcs: ["main.cpp"], + static_libs: [ + "libhealth_storage_default_impl", + ], +} diff --git a/health/storage/aidl/default/Storage.cpp b/health/storage/aidl/default/Storage.cpp new file mode 100644 index 0000000000..faa4ff6e60 --- /dev/null +++ b/health/storage/aidl/default/Storage.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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 "Storage.h" + +#include + +#include +#include + +using ::android::hardware::health::storage::DebugDump; +using ::android::hardware::health::storage::GarbageCollect; + +using HResult = android::hardware::health::storage::V1_0::Result; +using AResult = aidl::android::hardware::health::storage::Result; +// Ensure static_cast(any HResult) works +static_assert(static_cast(HResult::SUCCESS) == AResult::SUCCESS); +static_assert(static_cast(HResult::IO_ERROR) == AResult::IO_ERROR); +static_assert(static_cast(HResult::UNKNOWN_ERROR) == AResult::UNKNOWN_ERROR); + +namespace aidl::android::hardware::health::storage { + +ndk::ScopedAStatus Storage::garbageCollect( + int64_t timeout_seconds, const std::shared_ptr& callback) { + AResult result = static_cast(GarbageCollect(static_cast(timeout_seconds))); + if (callback != nullptr) { + auto status = callback->onFinish(result); + if (!status.isOk()) { + LOG(WARNING) << "Cannot return result " << toString(result) + << " to callback: " << status.getDescription(); + } + } + return ndk::ScopedAStatus::ok(); +} + +binder_status_t Storage::dump(int fd, const char**, uint32_t) { + DebugDump(fd); + return STATUS_OK; +} + +} // namespace aidl::android::hardware::health::storage diff --git a/health/storage/aidl/default/Storage.h b/health/storage/aidl/default/Storage.h new file mode 100644 index 0000000000..049991b679 --- /dev/null +++ b/health/storage/aidl/default/Storage.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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. + */ + +#pragma once + +#include + +namespace aidl::android::hardware::health::storage { + +class Storage : public BnStorage { + ndk::ScopedAStatus garbageCollect( + int64_t timeout_seconds, + const std::shared_ptr& callback) override; + binder_status_t dump(int fd, const char** args, uint32_t num_args) override; +}; + +} // namespace aidl::android::hardware::health::storage diff --git a/health/storage/aidl/default/health-storage-default.rc b/health/storage/aidl/default/health-storage-default.rc new file mode 100644 index 0000000000..fc1cc8b3a5 --- /dev/null +++ b/health/storage/aidl/default/health-storage-default.rc @@ -0,0 +1,7 @@ +service vendor.health-storage-default /vendor/bin/hw/android.hardware.health.storage-service.default + interface aidl android.hardware.health.storage.IStorage/default + oneshot + disabled + class hal + user system + group system diff --git a/health/storage/aidl/default/health-storage-default.xml b/health/storage/aidl/default/health-storage-default.xml new file mode 100644 index 0000000000..14d4901823 --- /dev/null +++ b/health/storage/aidl/default/health-storage-default.xml @@ -0,0 +1,7 @@ + + + android.hardware.health.storage + 1 + IStorage/default + + diff --git a/health/storage/aidl/default/main.cpp b/health/storage/aidl/default/main.cpp new file mode 100644 index 0000000000..186b64c0c5 --- /dev/null +++ b/health/storage/aidl/default/main.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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 "Storage.h" + +using aidl::android::hardware::health::storage::Storage; +using std::string_literals::operator""s; + +int main() { + ABinderProcess_setThreadPoolMaxThreadCount(0); + + // make a default storage service + auto storage = ndk::SharedRefBase::make(); + const std::string name = Storage::descriptor + "/default"s; + CHECK_EQ(STATUS_OK, + AServiceManager_registerLazyService(storage->asBinder().get(), name.c_str())); + + ABinderProcess_joinThreadPool(); + return EXIT_FAILURE; // should not reach +} From 571f926977cf28f301916d37741e5ef5a7584e0e Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 15 Jan 2021 17:24:27 -0800 Subject: [PATCH 4/5] health storage: refactor common code for test Test: pass Bug: 177470478 Change-Id: I7be46664df08fd600143ca018885c64030e8d6a1 --- health/storage/1.0/vts/functional/Android.bp | 3 + .../VtsHalHealthStorageV1_0TargetTest.cpp | 77 +++++-------------- health/storage/test_common/Android.bp | 20 +++++ .../include/health-storage-test/common.h | 69 +++++++++++++++++ 4 files changed, 110 insertions(+), 59 deletions(-) create mode 100644 health/storage/test_common/Android.bp create mode 100644 health/storage/test_common/include/health-storage-test/common.h diff --git a/health/storage/1.0/vts/functional/Android.bp b/health/storage/1.0/vts/functional/Android.bp index 22010319a2..731ad62434 100644 --- a/health/storage/1.0/vts/functional/Android.bp +++ b/health/storage/1.0/vts/functional/Android.bp @@ -19,6 +19,9 @@ cc_test { defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalHealthStorageV1_0TargetTest.cpp"], static_libs: ["android.hardware.health.storage@1.0"], + header_libs: [ + "libhealth_storage_test_common_headers", + ], shared_libs: [ "libhidlbase", ], diff --git a/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp b/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp index 24ddc5d814..ddb6b5a1fd 100644 --- a/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp +++ b/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.cpp @@ -14,14 +14,17 @@ * limitations under the License. */ +#include + +#include + #include #include #include +#include #include #include #include -#include -#include namespace android { namespace hardware { @@ -29,61 +32,17 @@ namespace health { namespace storage { namespace V1_0 { +using namespace ::android::hardware::health::storage::test; using ::std::literals::chrono_literals::operator""ms; #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) << ret.description() -// Dev GC timeout. This is the timeout used by vold. -const uint64_t kDevGcTimeoutSec = 120; -const std::chrono::seconds kDevGcTimeout{kDevGcTimeoutSec}; -// Dev GC timeout tolerance. The HAL may not immediately return after the -// timeout, so include an acceptable tolerance. -const std::chrono::seconds kDevGcTolerance{3}; -// Time accounted for RPC calls. -const std::chrono::milliseconds kRpcTime{1000}; - -template -std::string toString(std::chrono::duration time) { - return std::to_string(time.count()) + "ms"; -} - -/** An atomic boolean flag that indicates whether a task has finished. */ -class Flag { - public: - void onFinish() { - std::unique_lock lock(mMutex); - onFinishLocked(&lock); - } - template - bool wait(std::chrono::duration duration) { - std::unique_lock lock(mMutex); - return waitLocked(&lock, duration); - } - - protected: - /** Will unlock. */ - void onFinishLocked(std::unique_lock* lock) { - mFinished = true; - lock->unlock(); - mCv.notify_all(); - } - template - bool waitLocked(std::unique_lock* lock, std::chrono::duration duration) { - mCv.wait_for(*lock, duration, [this] { return mFinished; }); - return mFinished; - } - - bool mFinished{false}; - std::mutex mMutex; - std::condition_variable mCv; -}; - class GcCallback : public IGarbageCollectCallback, public Flag { - public: + public: Return onFinish(Result result) override { - std::unique_lock lock(mMutex); - mResult = result; - Flag::onFinishLocked(&lock); + std::unique_lock lock(mutex_); + result_ = result; + Flag::OnFinishLocked(&lock); return Void(); } @@ -93,13 +52,13 @@ class GcCallback : public IGarbageCollectCallback, public Flag { */ template void waitForResult(std::chrono::duration timeout, Result expected) { - std::unique_lock lock(mMutex); - ASSERT_TRUE(waitLocked(&lock, timeout)) << "timeout after " << toString(timeout); - EXPECT_EQ(expected, mResult); + std::unique_lock lock(mutex_); + ASSERT_TRUE(WaitLocked(&lock, timeout)) << "timeout after " << to_string(timeout); + EXPECT_EQ(expected, result_); } - private: - Result mResult{Result::UNKNOWN_ERROR}; + private: + Result result_{Result::UNKNOWN_ERROR}; }; class HealthStorageHidlTest : public ::testing::TestWithParam { @@ -127,10 +86,10 @@ class HealthStorageHidlTest : public ::testing::TestWithParam { auto pingFlag = std::make_shared(); std::thread([service, pingFlag] { service->ping(); - pingFlag->onFinish(); + pingFlag->OnFinish(); }) .detach(); - return pingFlag->wait(timeout); + return pingFlag->Wait(timeout); } sp fs; @@ -147,7 +106,7 @@ TEST_P(HealthStorageHidlTest, GcNullCallback) { // Hold test process because HAL can be single-threaded and doing GC. ASSERT_TRUE(ping(kDevGcTimeout + kDevGcTolerance + kRpcTime)) << "Service must be available after " - << toString(kDevGcTimeout + kDevGcTolerance + kRpcTime); + << to_string(kDevGcTimeout + kDevGcTolerance + kRpcTime); } /** diff --git a/health/storage/test_common/Android.bp b/health/storage/test_common/Android.bp new file mode 100644 index 0000000000..7c6bef414c --- /dev/null +++ b/health/storage/test_common/Android.bp @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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. + */ + +cc_library_headers { + name: "libhealth_storage_test_common_headers", + export_include_dirs: ["include"], +} diff --git a/health/storage/test_common/include/health-storage-test/common.h b/health/storage/test_common/include/health-storage-test/common.h new file mode 100644 index 0000000000..dfda83051d --- /dev/null +++ b/health/storage/test_common/include/health-storage-test/common.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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. + */ + +#pragma once + +#include +#include + +namespace android::hardware::health::storage::test { + +// Dev GC timeout. This is the timeout used by vold. +const uint64_t kDevGcTimeoutSec = 120; +const std::chrono::seconds kDevGcTimeout{kDevGcTimeoutSec}; +// Dev GC timeout tolerance. The HAL may not immediately return after the +// timeout, so include an acceptable tolerance. +const std::chrono::seconds kDevGcTolerance{3}; +// Time accounted for RPC calls. +const std::chrono::milliseconds kRpcTime{1000}; + +template +std::string to_string(std::chrono::duration time) { + return std::to_string(time.count()) + "ms"; +} + +/** An atomic boolean flag that indicates whether a task has finished. */ +class Flag { + public: + void OnFinish() { + std::unique_lock lock(mutex_); + OnFinishLocked(&lock); + } + template + bool Wait(std::chrono::duration duration) { + std::unique_lock lock(mutex_); + return WaitLocked(&lock, duration); + } + + protected: + /** Will unlock. */ + void OnFinishLocked(std::unique_lock* lock) { + finished_ = true; + lock->unlock(); + cv_.notify_all(); + } + template + bool WaitLocked(std::unique_lock* lock, std::chrono::duration duration) { + cv_.wait_for(*lock, duration, [this] { return finished_; }); + return finished_; + } + + bool finished_{false}; + std::mutex mutex_; + std::condition_variable cv_; +}; + +} // namespace android::hardware::health::storage::test From 22feb0aaa53cb1c1ca284e0905fc2d0fe7df9073 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 15 Jan 2021 18:18:32 -0800 Subject: [PATCH 5/5] health storage AIDL VTS test. Test: run it Bug: 177470478 Change-Id: I1d0091f14c57b06dc37eda28ec1db3bc0bf7d251 --- health/storage/aidl/vts/functional/Android.bp | 37 +++++ .../VtsHalHealthStorageTargetTest.cpp | 136 ++++++++++++++++++ .../VtsHalHealthStorageTargetTest.xml | 33 +++++ 3 files changed, 206 insertions(+) create mode 100644 health/storage/aidl/vts/functional/Android.bp create mode 100644 health/storage/aidl/vts/functional/VtsHalHealthStorageTargetTest.cpp create mode 100644 health/storage/aidl/vts/functional/VtsHalHealthStorageTargetTest.xml diff --git a/health/storage/aidl/vts/functional/Android.bp b/health/storage/aidl/vts/functional/Android.bp new file mode 100644 index 0000000000..86b72a712d --- /dev/null +++ b/health/storage/aidl/vts/functional/Android.bp @@ -0,0 +1,37 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// 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. + +cc_test { + name: "VtsHalHealthStorageTargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "VtsHalHealthStorageTargetTest.cpp", + ], + shared_libs: [ + "libbinder_ndk", + ], + static_libs: [ + "android.hardware.health.storage-ndk_platform", + ], + header_libs: [ + "libhealth_storage_test_common_headers", + ], + test_suites: [ + "vts", + ], + test_config: "VtsHalHealthStorageTargetTest.xml", +} diff --git a/health/storage/aidl/vts/functional/VtsHalHealthStorageTargetTest.cpp b/health/storage/aidl/vts/functional/VtsHalHealthStorageTargetTest.cpp new file mode 100644 index 0000000000..3b6b6b4864 --- /dev/null +++ b/health/storage/aidl/vts/functional/VtsHalHealthStorageTargetTest.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace aidl::android::hardware::health::storage { + +using namespace ::android::hardware::health::storage::test; +using std::chrono_literals::operator""ms; + +#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) << ret.getDescription() +#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk()) << ret.getDescription() + +class GcCallback : public BnGarbageCollectCallback, public Flag { + public: + ndk::ScopedAStatus onFinish(Result result) override { + std::unique_lock lock(mutex_); + result_ = result; + OnFinishLocked(&lock); + return ndk::ScopedAStatus::ok(); + } + + /** + * Wait for a specific "timeout". If GC has finished, test that the result + * is equal to the "expected" value. + */ + template + void WaitForResult(std::chrono::duration timeout, Result expected) { + std::unique_lock lock(mutex_); + ASSERT_TRUE(WaitLocked(&lock, timeout)) << "timeout after " << to_string(timeout); + EXPECT_EQ(expected, result_); + } + + private: + Result result_{Result::UNKNOWN_ERROR}; +}; + +class HealthStorageAidl : public testing::TestWithParam { + public: + virtual void SetUp() override { + std::string name = GetParam(); + ASSERT_TRUE(AServiceManager_isDeclared(name.c_str())) << name; + ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str())); + ASSERT_NE(binder, nullptr); + storage_ = IStorage::fromBinder(binder); + ASSERT_NE(storage_, nullptr); + } + + virtual void TearDown() override { + EXPECT_TRUE(ping(kRpcTime)) + << "Service is not responsive; expect subsequent tests to fail."; + } + + /** + * Ping the service and expect it to return after "timeout". Return true + * iff the service is responsive within "timeout". + */ + template + bool ping(std::chrono::duration timeout) { + // Ensure the service is responsive after the test. + std::shared_ptr service = storage_; + auto ping_flag = std::make_shared(); + std::thread([service, ping_flag] { + EXPECT_EQ(STATUS_OK, AIBinder_ping(service->asBinder().get())); + ping_flag->OnFinish(); + }).detach(); + return ping_flag->Wait(timeout); + } + + std::shared_ptr storage_; +}; + +/** + * Ensure garbage collection works on null callback. + */ +TEST_P(HealthStorageAidl, GcNullCallback) { + ASSERT_OK(storage_->garbageCollect(kDevGcTimeoutSec, nullptr)); + + // Hold test process because HAL can be single-threaded and doing GC. + ASSERT_TRUE(ping(kDevGcTimeout + kDevGcTolerance + kRpcTime)) + << "Service must be available after " + << to_string(kDevGcTimeout + kDevGcTolerance + kRpcTime); +} + +/** + * Ensure garbage collection works on non-null callback. + */ +TEST_P(HealthStorageAidl, GcNonNullCallback) { + std::shared_ptr cb = ndk::SharedRefBase::make(); + ASSERT_OK(storage_->garbageCollect(kDevGcTimeoutSec, cb)); + cb->WaitForResult(kDevGcTimeout + kDevGcTolerance + kRpcTime, Result::SUCCESS); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HealthStorageAidl); +INSTANTIATE_TEST_SUITE_P( + HealthStorage, HealthStorageAidl, + testing::ValuesIn(::android::getAidlHalInstanceNames(IStorage::descriptor)), + ::android::PrintInstanceNameToString); + +} // namespace aidl::android::hardware::health::storage + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); + return RUN_ALL_TESTS(); +} diff --git a/health/storage/aidl/vts/functional/VtsHalHealthStorageTargetTest.xml b/health/storage/aidl/vts/functional/VtsHalHealthStorageTargetTest.xml new file mode 100644 index 0000000000..f8a1c87a34 --- /dev/null +++ b/health/storage/aidl/vts/functional/VtsHalHealthStorageTargetTest.xml @@ -0,0 +1,33 @@ + + + +