Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28290190 authored by Yifan Hong's avatar Yifan Hong Committed by Gerrit Code Review
Browse files

Merge changes from topic "health_storage_aidl"

* changes:
  health storage AIDL VTS test.
  health storage: refactor common code for test
  Add default impl for health storage AIDL HAL
  Add health.storage AIDL HAL
  Refactor common implementation for health storage HAL.
parents d7459717 22feb0aa
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -266,6 +266,14 @@
            <instance>default</instance>
        </interface>
    </hal>
    <hal format="aidl" optional="true">
        <name>android.hardware.health.storage</name>
        <version>1</version>
        <interface>
            <name>IStorage</name>
            <instance>default</instance>
        </interface>
    </hal>
    <hal format="aidl" optional="true">
        <name>android.hardware.identity</name>
        <version>1-2</version>
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ cc_binary {
    ],

    static_libs: [
        "libhealth_storage_impl_common",
        "libfstab",
    ],

+3 −87
Original line number Diff line number Diff line
@@ -18,11 +18,8 @@

#include <sstream>

#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
#include <fstab/fstab.h>
#include <health-storage-impl/common.h>

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<void> Storage::garbageCollect(uint64_t timeoutSeconds,
                                     const sp<IGarbageCollectCallback>& 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<void> Storage::debug(const hidl_handle& handle, const hidl_vec<hidl_strin
    }

    int fd = handle->data[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();
}
+3 −0
Original line number Diff line number Diff line
@@ -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",
    ],
+18 −59
Original line number Diff line number Diff line
@@ -14,14 +14,17 @@
 * limitations under the License.
 */

#include <unistd.h>

#include <thread>

#include <android-base/logging.h>
#include <android/hardware/health/storage/1.0/IStorage.h>
#include <gtest/gtest.h>
#include <health-storage-test/common.h>
#include <hidl/GtestPrinter.h>
#include <hidl/HidlTransportSupport.h>
#include <hidl/ServiceManagement.h>
#include <unistd.h>
#include <thread>

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 <typename R>
std::string toString(std::chrono::duration<R, std::milli> 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<std::mutex> lock(mMutex);
        onFinishLocked(&lock);
    }
    template <typename R, typename P>
    bool wait(std::chrono::duration<R, P> duration) {
        std::unique_lock<std::mutex> lock(mMutex);
        return waitLocked(&lock, duration);
    }

   protected:
    /** Will unlock. */
    void onFinishLocked(std::unique_lock<std::mutex>* lock) {
        mFinished = true;
        lock->unlock();
        mCv.notify_all();
    }
    template <typename R, typename P>
    bool waitLocked(std::unique_lock<std::mutex>* lock, std::chrono::duration<R, P> 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:
    Return<void> onFinish(Result result) override {
        std::unique_lock<std::mutex> lock(mMutex);
        mResult = result;
        Flag::onFinishLocked(&lock);
        std::unique_lock<std::mutex> lock(mutex_);
        result_ = result;
        Flag::OnFinishLocked(&lock);
        return Void();
    }

@@ -93,13 +52,13 @@ class GcCallback : public IGarbageCollectCallback, public Flag {
     */
    template <typename R, typename P>
    void waitForResult(std::chrono::duration<R, P> timeout, Result expected) {
        std::unique_lock<std::mutex> lock(mMutex);
        ASSERT_TRUE(waitLocked(&lock, timeout)) << "timeout after " << toString(timeout);
        EXPECT_EQ(expected, mResult);
        std::unique_lock<std::mutex> lock(mutex_);
        ASSERT_TRUE(WaitLocked(&lock, timeout)) << "timeout after " << to_string(timeout);
        EXPECT_EQ(expected, result_);
    }

  private:
    Result mResult{Result::UNKNOWN_ERROR};
    Result result_{Result::UNKNOWN_ERROR};
};

class HealthStorageHidlTest : public ::testing::TestWithParam<std::string> {
@@ -127,10 +86,10 @@ class HealthStorageHidlTest : public ::testing::TestWithParam<std::string> {
        auto pingFlag = std::make_shared<Flag>();
        std::thread([service, pingFlag] {
            service->ping();
            pingFlag->onFinish();
            pingFlag->OnFinish();
        })
            .detach();
        return pingFlag->wait(timeout);
        return pingFlag->Wait(timeout);
    }

    sp<IStorage> 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);
}

/**
Loading