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

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

Merge changes from topic "libsnapshot_fuzzer_test"

* changes:
  libsnapshot_fuzzer: Properly unmap images
  Reland "libsnapshot_fuzzer: Add tests"
parents f3a570b8 3013e6ef
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -14,6 +14,9 @@
    },
    {
      "name": "vts_libsnapshot_test"
    },
    {
      "name": "libsnapshot_fuzzer_test"
    }
  ]
}
+18 −2
Original line number Diff line number Diff line
@@ -246,8 +246,8 @@ cc_test {
    gtest: false,
}

cc_fuzz {
    name: "libsnapshot_fuzzer",
cc_defaults {
    name: "libsnapshot_fuzzer_defaults",

    // TODO(b/154633114): make host supported.
    // host_supported: true,
@@ -289,6 +289,11 @@ cc_fuzz {
        canonical_path_from_root: false,
        local_include_dirs: ["."],
    },
}

cc_fuzz {
    name: "libsnapshot_fuzzer",
    defaults: ["libsnapshot_fuzzer_defaults"],
    corpus: ["corpus/*"],
    fuzz_config: {
        cc: ["android-virtual-ab+bugs@google.com"],
@@ -298,3 +303,14 @@ cc_fuzz {
        fuzz_on_haiku_device: true,
    },
}

cc_test {
    name: "libsnapshot_fuzzer_test",
    defaults: ["libsnapshot_fuzzer_defaults"],
    data: ["corpus/*"],
    test_suites: [
        "device-tests",
    ],
    auto_gen_config: true,
    require_root: true,
}
+70 −50
Original line number Diff line number Diff line
@@ -68,17 +68,25 @@ int CheckConsistency() {
    return 0;
}

// Get the field descriptor for the oneof field in the action message. If no oneof field is set,
// return nullptr.
template <typename Action>
void ExecuteActionProto(typename Action::Class* module,
const google::protobuf::FieldDescriptor* GetValueFieldDescriptor(
        const typename Action::Proto& action_proto) {
    static auto* action_value_desc = GetProtoValueDescriptor(Action::Proto::GetDescriptor());

    auto* action_refl = Action::Proto::GetReflection();
    if (!action_refl->HasOneof(action_proto, action_value_desc)) {
        return;
        return nullptr;
    }
    return action_refl->GetOneofFieldDescriptor(action_proto, action_value_desc);
}

    const auto* field_desc = action_refl->GetOneofFieldDescriptor(action_proto, action_value_desc);
template <typename Action>
void ExecuteActionProto(typename Action::ClassType* module,
                        const typename Action::Proto& action_proto) {
    const auto* field_desc = GetValueFieldDescriptor<Action>(action_proto);
    if (field_desc == nullptr) return;
    auto number = field_desc->number();
    const auto& map = *Action::GetFunctionMap();
    auto it = map.find(number);
@@ -89,7 +97,7 @@ void ExecuteActionProto(typename Action::Class* module,

template <typename Action>
void ExecuteAllActionProtos(
        typename Action::Class* module,
        typename Action::ClassType* module,
        const google::protobuf::RepeatedPtrField<typename Action::Proto>& action_protos) {
    for (const auto& proto : action_protos) {
        ExecuteActionProto<Action>(module, proto);
@@ -134,53 +142,57 @@ FUZZ_DEFINE_PRIMITIVE_GETTER(float, GetFloat);
// ActionPerformer extracts arguments from the protobuf message, and then call FuzzFunction
// with these arguments.
template <typename FuzzFunction, typename Signature, typename Enabled = void>
struct ActionPerfomer;  // undefined
struct ActionPerformerImpl;  // undefined

template <typename FuzzFunction, typename MessageProto>
struct ActionPerfomer<
struct ActionPerformerImpl<
        FuzzFunction, void(const MessageProto&),
        typename std::enable_if_t<std::is_base_of_v<google::protobuf::Message, MessageProto>>> {
    static void Invoke(typename FuzzFunction::Class* module,
                       const google::protobuf::Message& action_proto,
    static typename FuzzFunction::ReturnType Invoke(
            typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
            const google::protobuf::FieldDescriptor* field_desc) {
        const MessageProto& arg = CheckedCast<std::remove_reference_t<MessageProto>>(
                action_proto.GetReflection()->GetMessage(action_proto, field_desc));
        FuzzFunction::ImplBody(module, arg);
        return FuzzFunction::ImplBody(module, arg);
    }
};

template <typename FuzzFunction, typename Primitive>
struct ActionPerfomer<FuzzFunction, void(Primitive),
struct ActionPerformerImpl<FuzzFunction, void(Primitive),
                           typename std::enable_if_t<std::is_arithmetic_v<Primitive>>> {
    static void Invoke(typename FuzzFunction::Class* module,
                       const google::protobuf::Message& action_proto,
    static typename FuzzFunction::ReturnType Invoke(
            typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
            const google::protobuf::FieldDescriptor* field_desc) {
        Primitive arg = std::invoke(PrimitiveGetter<Primitive>::fp, action_proto.GetReflection(),
                                    action_proto, field_desc);
        FuzzFunction::ImplBody(module, arg);
        return FuzzFunction::ImplBody(module, arg);
    }
};

template <typename FuzzFunction>
struct ActionPerfomer<FuzzFunction, void()> {
    static void Invoke(typename FuzzFunction::Class* module, const google::protobuf::Message&,
struct ActionPerformerImpl<FuzzFunction, void()> {
    static typename FuzzFunction::ReturnType Invoke(typename FuzzFunction::ClassType* module,
                                                    const google::protobuf::Message&,
                                                    const google::protobuf::FieldDescriptor*) {
        FuzzFunction::ImplBody(module);
        return FuzzFunction::ImplBody(module);
    }
};

template <typename FuzzFunction>
struct ActionPerfomer<FuzzFunction, void(const std::string&)> {
    static void Invoke(typename FuzzFunction::Class* module,
                       const google::protobuf::Message& action_proto,
struct ActionPerformerImpl<FuzzFunction, void(const std::string&)> {
    static typename FuzzFunction::ReturnType Invoke(
            typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
            const google::protobuf::FieldDescriptor* field_desc) {
        std::string scratch;
        const std::string& arg = action_proto.GetReflection()->GetStringReference(
                action_proto, field_desc, &scratch);
        FuzzFunction::ImplBody(module, arg);
        return FuzzFunction::ImplBody(module, arg);
    }
};

template <typename FuzzFunction>
struct ActionPerformer : ActionPerformerImpl<FuzzFunction, typename FuzzFunction::Signature> {};

}  // namespace android::fuzz

// Fuzz existing C++ class, ClassType, with a collection of functions under the name Action.
@@ -197,11 +209,11 @@ struct ActionPerfomer<FuzzFunction, void(const std::string&)> {
//   FUZZ_CLASS(Foo, FooAction)
// After linking functions of Foo to FooAction, execute all actions by:
//   FooAction::ExecuteAll(foo_object, action_protos)
#define FUZZ_CLASS(ClassType, Action)                                                            \
#define FUZZ_CLASS(Class, Action)                                                                \
    class Action {                                                                               \
      public:                                                                                    \
        using Proto = Action##Proto;                                                             \
        using Class = ClassType;                                                                 \
        using ClassType = Class;                                                                 \
        using FunctionMap = android::fuzz::FunctionMap<Class>;                                   \
        static FunctionMap* GetFunctionMap() {                                                   \
            static Action::FunctionMap map;                                                      \
@@ -225,29 +237,33 @@ struct ActionPerfomer<FuzzFunction, void(const std::string&)> {
// }
// class Foo { public: void DoAwesomeFoo(bool arg); };
// FUZZ_OBJECT(FooAction, Foo);
// FUZZ_FUNCTION(FooAction, DoFoo, module, bool arg) {
// FUZZ_FUNCTION(FooAction, DoFoo, void, IFoo* module, bool arg) {
//   module->DoAwesomeFoo(arg);
// }
// The name DoFoo is the camel case name of the action in protobuf definition of FooActionProto.
#define FUZZ_FUNCTION(Action, FunctionName, module, ...)                                         \
#define FUZZ_FUNCTION(Action, FunctionName, Return, ModuleArg, ...)             \
    class FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName) {                      \
      public:                                                                   \
        using Class = Action::Class;                                                             \
        static void ImplBody(Action::Class*, ##__VA_ARGS__);                                     \
        using ActionType = Action;                                              \
        using ClassType = Action::ClassType;                                    \
        using ReturnType = Return;                                              \
        using Signature = void(__VA_ARGS__);                                    \
        static constexpr const char name[] = #FunctionName;                     \
        static constexpr const auto tag =                                       \
                Action::Proto::ValueCase::FUZZ_FUNCTION_TAG_NAME(FunctionName); \
        static ReturnType ImplBody(ModuleArg, ##__VA_ARGS__);                   \
                                                                                \
      private:                                                                  \
        static bool registered_;                                                \
    };                                                                          \
    auto FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::registered_ = ([] {    \
        auto tag = Action::Proto::ValueCase::FUZZ_FUNCTION_TAG_NAME(FunctionName);               \
        auto func =                                                                              \
                &::android::fuzz::ActionPerfomer<FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName), \
                                                 void(__VA_ARGS__)>::Invoke;                     \
        auto tag = FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::tag;         \
        auto func = &::android::fuzz::ActionPerformer<FUZZ_FUNCTION_CLASS_NAME( \
                Action, FunctionName)>::Invoke;                                 \
        Action::GetFunctionMap()->CheckEmplace(tag, func);                      \
        return true;                                                            \
    })();                                                                       \
    void FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::ImplBody(Action::Class* module,         \
                                                                  ##__VA_ARGS__)
    Return FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::ImplBody(ModuleArg, ##__VA_ARGS__)

// Implement a simple action by linking it to the function with the same name. Example:
// message FooActionProto {
@@ -262,4 +278,8 @@ struct ActionPerfomer<FuzzFunction, void(const std::string&)> {
// The name DoBar is the camel case name of the action in protobuf definition of FooActionProto, and
// also the name of the function of Foo.
#define FUZZ_SIMPLE_FUNCTION(Action, FunctionName)                            \
    FUZZ_FUNCTION(Action, FunctionName, module) { (void)module->FunctionName(); }
    FUZZ_FUNCTION(Action, FunctionName,                                       \
                  decltype(std::declval<Action::ClassType>().FunctionName()), \
                  Action::ClassType* module) {                                \
        return module->FunctionName();                                        \
    }
+157 −32
Original line number Diff line number Diff line
@@ -21,14 +21,21 @@
#include <tuple>

#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/result.h>
#include <gtest/gtest.h>
#include <src/libfuzzer/libfuzzer_macro.h>
#include <storage_literals/storage_literals.h>

#include "fuzz_utils.h"
#include "snapshot_fuzz_utils.h"

using android::base::Error;
using android::base::GetBoolProperty;
using android::base::LogId;
using android::base::LogSeverity;
using android::base::ReadFileToString;
using android::base::Result;
using android::base::SetLogger;
using android::base::StderrLogger;
using android::base::StdioLogger;
@@ -37,6 +44,8 @@ using android::fuzz::CheckedCast;
using android::snapshot::SnapshotFuzzData;
using android::snapshot::SnapshotFuzzEnv;
using chromeos_update_engine::DeltaArchiveManifest;
using google::protobuf::FieldDescriptor;
using google::protobuf::Message;
using google::protobuf::RepeatedPtrField;

// Avoid linking to libgsi since it needs disk I/O.
@@ -74,48 +83,49 @@ FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, RecoveryCreateSnapshotDevices);
FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, EnsureMetadataMounted);
FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, GetSnapshotMergeStatsInstance);

#define SNAPSHOT_FUZZ_FUNCTION(FunctionName, ...) \
    FUZZ_FUNCTION(SnapshotManagerAction, FunctionName, snapshot, ##__VA_ARGS__)
#define SNAPSHOT_FUZZ_FUNCTION(FunctionName, ReturnType, ...)                                  \
    FUZZ_FUNCTION(SnapshotManagerAction, FunctionName, ReturnType, ISnapshotManager* snapshot, \
                  ##__VA_ARGS__)

SNAPSHOT_FUZZ_FUNCTION(FinishedSnapshotWrites, bool wipe) {
    (void)snapshot->FinishedSnapshotWrites(wipe);
SNAPSHOT_FUZZ_FUNCTION(FinishedSnapshotWrites, bool, bool wipe) {
    return snapshot->FinishedSnapshotWrites(wipe);
}

SNAPSHOT_FUZZ_FUNCTION(ProcessUpdateState, const ProcessUpdateStateArgs& args) {
SNAPSHOT_FUZZ_FUNCTION(ProcessUpdateState, bool, const ProcessUpdateStateArgs& args) {
    std::function<bool()> before_cancel;
    if (args.has_before_cancel()) {
        before_cancel = [&]() { return args.fail_before_cancel(); };
    }
    (void)snapshot->ProcessUpdateState({}, before_cancel);
    return snapshot->ProcessUpdateState({}, before_cancel);
}

SNAPSHOT_FUZZ_FUNCTION(GetUpdateState, bool has_progress_arg) {
SNAPSHOT_FUZZ_FUNCTION(GetUpdateState, UpdateState, bool has_progress_arg) {
    double progress;
    (void)snapshot->GetUpdateState(has_progress_arg ? &progress : nullptr);
    return snapshot->GetUpdateState(has_progress_arg ? &progress : nullptr);
}

SNAPSHOT_FUZZ_FUNCTION(HandleImminentDataWipe, bool has_callback) {
SNAPSHOT_FUZZ_FUNCTION(HandleImminentDataWipe, bool, bool has_callback) {
    std::function<void()> callback;
    if (has_callback) {
        callback = []() {};
    }
    (void)snapshot->HandleImminentDataWipe(callback);
    return snapshot->HandleImminentDataWipe(callback);
}

SNAPSHOT_FUZZ_FUNCTION(Dump) {
SNAPSHOT_FUZZ_FUNCTION(Dump, bool) {
    std::stringstream ss;
    (void)snapshot->Dump(ss);
    return snapshot->Dump(ss);
}

SNAPSHOT_FUZZ_FUNCTION(CreateUpdateSnapshots, const DeltaArchiveManifest& manifest) {
    (void)snapshot->CreateUpdateSnapshots(manifest);
SNAPSHOT_FUZZ_FUNCTION(CreateUpdateSnapshots, bool, const DeltaArchiveManifest& manifest) {
    return snapshot->CreateUpdateSnapshots(manifest);
}

SNAPSHOT_FUZZ_FUNCTION(UnmapUpdateSnapshot, const std::string& name) {
    (void)snapshot->UnmapUpdateSnapshot(name);
SNAPSHOT_FUZZ_FUNCTION(UnmapUpdateSnapshot, bool, const std::string& name) {
    return snapshot->UnmapUpdateSnapshot(name);
}

SNAPSHOT_FUZZ_FUNCTION(CreateLogicalAndSnapshotPartitions,
SNAPSHOT_FUZZ_FUNCTION(CreateLogicalAndSnapshotPartitions, bool,
                       const CreateLogicalAndSnapshotPartitionsArgs& args) {
    const std::string* super;
    if (args.use_correct_super()) {
@@ -123,20 +133,21 @@ SNAPSHOT_FUZZ_FUNCTION(CreateLogicalAndSnapshotPartitions,
    } else {
        super = &args.super();
    }
    (void)snapshot->CreateLogicalAndSnapshotPartitions(
    return snapshot->CreateLogicalAndSnapshotPartitions(
            *super, std::chrono::milliseconds(args.timeout_millis()));
}

SNAPSHOT_FUZZ_FUNCTION(RecoveryCreateSnapshotDevicesWithMetadata,
SNAPSHOT_FUZZ_FUNCTION(RecoveryCreateSnapshotDevicesWithMetadata, CreateResult,
                       const RecoveryCreateSnapshotDevicesArgs& args) {
    std::unique_ptr<AutoDevice> device;
    if (args.has_metadata_device_object()) {
        device = std::make_unique<DummyAutoDevice>(args.metadata_mounted());
    }
    (void)snapshot->RecoveryCreateSnapshotDevices(device);
    return snapshot->RecoveryCreateSnapshotDevices(device);
}

SNAPSHOT_FUZZ_FUNCTION(MapUpdateSnapshot, const CreateLogicalPartitionParamsProto& params_proto) {
SNAPSHOT_FUZZ_FUNCTION(MapUpdateSnapshot, bool,
                       const CreateLogicalPartitionParamsProto& params_proto) {
    auto partition_opener = std::make_unique<TestPartitionOpener>(GetSnapshotFuzzEnv()->super());
    CreateLogicalPartitionParams params;
    if (params_proto.use_correct_super()) {
@@ -153,10 +164,10 @@ SNAPSHOT_FUZZ_FUNCTION(MapUpdateSnapshot, const CreateLogicalPartitionParamsProt
    params.device_name = params_proto.device_name();
    params.partition_opener = partition_opener.get();
    std::string path;
    (void)snapshot->MapUpdateSnapshot(params, &path);
    return snapshot->MapUpdateSnapshot(params, &path);
}

SNAPSHOT_FUZZ_FUNCTION(SwitchSlot) {
SNAPSHOT_FUZZ_FUNCTION(SwitchSlot, void) {
    (void)snapshot;
    CHECK(current_module != nullptr);
    CHECK(current_module->device_info != nullptr);
@@ -194,7 +205,8 @@ void FatalOnlyLogger(LogId logid, LogSeverity severity, const char* tag, const c
}
// Stop logging (except fatal messages) after global initialization. This is only done once.
int StopLoggingAfterGlobalInit() {
    [[maybe_unused]] static protobuf_mutator::protobuf::LogSilencer log_silincer;
    (void)GetSnapshotFuzzEnv();
    [[maybe_unused]] static protobuf_mutator::protobuf::LogSilencer log_silencer;
    SetLogger(&FatalOnlyLogger);
    return 0;
}
@@ -202,15 +214,10 @@ int StopLoggingAfterGlobalInit() {
SnapshotFuzzEnv* GetSnapshotFuzzEnv() {
    [[maybe_unused]] static auto allow_logging = AllowLoggingDuringGlobalInit();
    static SnapshotFuzzEnv env;
    [[maybe_unused]] static auto stop_logging = StopLoggingAfterGlobalInit();
    return &env;
}

}  // namespace android::snapshot

DEFINE_PROTO_FUZZER(const SnapshotFuzzData& snapshot_fuzz_data) {
    using namespace android::snapshot;

SnapshotTestModule SetUpTest(const SnapshotFuzzData& snapshot_fuzz_data) {
    current_data = &snapshot_fuzz_data;

    auto env = GetSnapshotFuzzEnv();
@@ -219,9 +226,127 @@ DEFINE_PROTO_FUZZER(const SnapshotFuzzData& snapshot_fuzz_data) {
    auto test_module = env->CheckCreateSnapshotManager(snapshot_fuzz_data);
    current_module = &test_module;
    CHECK(test_module.snapshot);
    return test_module;
}

    SnapshotManagerAction::ExecuteAll(test_module.snapshot.get(), snapshot_fuzz_data.actions());

void TearDownTest() {
    current_module = nullptr;
    current_data = nullptr;
}

}  // namespace android::snapshot

DEFINE_PROTO_FUZZER(const SnapshotFuzzData& snapshot_fuzz_data) {
    using namespace android::snapshot;

    [[maybe_unused]] static auto stop_logging = StopLoggingAfterGlobalInit();
    auto test_module = SetUpTest(snapshot_fuzz_data);
    SnapshotManagerAction::ExecuteAll(test_module.snapshot.get(), snapshot_fuzz_data.actions());
    TearDownTest();
}

namespace android::snapshot {

// Work-around to cast a 'void' value to Result<void>.
template <typename T>
struct GoodResult {
    template <typename F>
    static Result<T> Cast(F&& f) {
        return f();
    }
};

template <>
struct GoodResult<void> {
    template <typename F>
    static Result<void> Cast(F&& f) {
        f();
        return {};
    }
};

class LibsnapshotFuzzerTest : public ::testing::Test {
  protected:
    static void SetUpTestCase() {
        // Do initialization once.
        (void)GetSnapshotFuzzEnv();
    }
    void SetUp() override {
        bool is_virtual_ab = GetBoolProperty("ro.virtual_ab.enabled", false);
        if (!is_virtual_ab) GTEST_SKIP() << "Test only runs on Virtual A/B devices.";
    }
    void SetUpFuzzData(const std::string& fn) {
        auto path = android::base::GetExecutableDirectory() + "/corpus/"s + fn;
        std::string proto_text;
        ASSERT_TRUE(ReadFileToString(path, &proto_text));
        snapshot_fuzz_data_ = std::make_unique<SnapshotFuzzData>();
        ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(proto_text,
                                                                  snapshot_fuzz_data_.get()));
        test_module_ = android::snapshot::SetUpTest(*snapshot_fuzz_data_);
    }
    void TearDown() override { android::snapshot::TearDownTest(); }
    template <typename FuzzFunction>
    Result<typename FuzzFunction::ReturnType> Execute(int action_index) {
        if (action_index >= snapshot_fuzz_data_->actions_size()) {
            return Error() << "Index " << action_index << " is out of bounds ("
                           << snapshot_fuzz_data_->actions_size() << " actions in corpus";
        }
        const auto& action_proto = snapshot_fuzz_data_->actions(action_index);
        const auto* field_desc =
                android::fuzz::GetValueFieldDescriptor<typename FuzzFunction::ActionType>(
                        action_proto);
        if (field_desc == nullptr) {
            return Error() << "Action at index " << action_index << " has no value defined.";
        }
        if (FuzzFunction::tag != field_desc->number()) {
            return Error() << "Action at index " << action_index << " is expected to be "
                           << FuzzFunction::name << ", but it is " << field_desc->name()
                           << " in corpus.";
        }
        return GoodResult<typename FuzzFunction::ReturnType>::Cast([&]() {
            return android::fuzz::ActionPerformer<FuzzFunction>::Invoke(test_module_.snapshot.get(),
                                                                        action_proto, field_desc);
        });
    }

    std::unique_ptr<SnapshotFuzzData> snapshot_fuzz_data_;
    SnapshotTestModule test_module_;
};

#define SNAPSHOT_FUZZ_FN_NAME(name) FUZZ_FUNCTION_CLASS_NAME(SnapshotManagerAction, name)

MATCHER_P(ResultIs, expected, "") {
    if (!arg.ok()) {
        *result_listener << arg.error();
        return false;
    }
    *result_listener << "expected: " << expected;
    return arg.value() == expected;
}

#define ASSERT_RESULT_TRUE(actual) ASSERT_THAT(actual, ResultIs(true))

// Check that launch_device.txt is executed correctly.
TEST_F(LibsnapshotFuzzerTest, LaunchDevice) {
    SetUpFuzzData("launch_device.txt");

    int i = 0;
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(BeginUpdate)>(i++));
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(CreateUpdateSnapshots)>(i++));
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "sys_b";
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "vnd_b";
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "prd_b";
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(FinishedSnapshotWrites)>(i++));
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "sys_b";
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "vnd_b";
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "prd_b";
    ASSERT_RESULT_OK(Execute<SNAPSHOT_FUZZ_FN_NAME(SwitchSlot)>(i++));
    ASSERT_EQ("_b", test_module_.device_info->GetSlotSuffix());
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(NeedSnapshotsInFirstStageMount)>(i++));
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(CreateLogicalAndSnapshotPartitions)>(i++));
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(InitiateMerge)>(i++));
    ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(ProcessUpdateState)>(i++));
    ASSERT_EQ(i, snapshot_fuzz_data_->actions_size()) << "Not all actions are executed.";
}

}  // namespace android::snapshot
+18 −12
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/properties.h>
#include <fs_mgr.h>
#include <libsnapshot/auto_device.h>
#include <libsnapshot/snapshot.h>
@@ -165,14 +164,6 @@ void InsertProperty(const char* key, const char* /*name*/, void* cookie) {
    reinterpret_cast<PropertyList*>(cookie)->insert(key);
}

void CheckUnsetGsidProps() {
    PropertyList list;
    property_list(&InsertProperty, reinterpret_cast<void*>(&list));
    for (const auto& key : list) {
        SetProperty(key, "");
    }
}

// Attempt to delete all devices that is based on dev_name, including itself.
void CheckDeleteDeviceMapperTree(const std::string& dev_name, bool known_allow_delete = false,
                                 uint64_t depth = 100) {
@@ -344,7 +335,6 @@ class AutoMemBasedDir : public AutoDevice {
};

SnapshotFuzzEnv::SnapshotFuzzEnv() {
    CheckUnsetGsidProps();
    CheckCleanupDeviceMapperDevices();
    CheckDetachLoopDevices();
    CheckUmountAll();
@@ -368,7 +358,6 @@ SnapshotFuzzEnv::SnapshotFuzzEnv() {
}

SnapshotFuzzEnv::~SnapshotFuzzEnv() {
    CheckUnsetGsidProps();
    CheckCleanupDeviceMapperDevices();
    mounted_data_ = nullptr;
    auto_delete_data_mount_point_ = nullptr;
@@ -396,7 +385,7 @@ std::unique_ptr<IImageManager> SnapshotFuzzEnv::CheckCreateFakeImageManager(
        const std::string& metadata_dir, const std::string& data_dir) {
    PCHECK(Mkdir(metadata_dir));
    PCHECK(Mkdir(data_dir));
    return ImageManager::Open(metadata_dir, data_dir);
    return SnapshotFuzzImageManager::Open(metadata_dir, data_dir);
}

// Helper to create a loop device for a file.
@@ -507,4 +496,21 @@ std::unique_ptr<AutoDevice> SnapshotFuzzEnv::CheckMountFormatData(const std::str
    return std::make_unique<AutoUnmount>(mount_point);
}

SnapshotFuzzImageManager::~SnapshotFuzzImageManager() {
    // Remove relevant gsid.mapped_images.* props.
    for (const auto& name : mapped_) {
        CHECK(UnmapImageIfExists(name)) << "Cannot unmap " << name;
    }
}

bool SnapshotFuzzImageManager::MapImageDevice(const std::string& name,
                                              const std::chrono::milliseconds& timeout_ms,
                                              std::string* path) {
    if (impl_->MapImageDevice(name, timeout_ms, path)) {
        mapped_.insert(name);
        return true;
    }
    return false;
}

}  // namespace android::snapshot
Loading