Add PropertyFetcher.

This is a mockable / replacable class for getting sysprops.
On host, sysprops may be provided via ADB or command line
arguments.
On device, default behavior is to use android-base/properties.h.

Bug: 72722951
Test: libvintf_test
Test: vintf_object_test

Change-Id: I752c4336dacd4c5f3254f32e4caf8dc743c636d9
diff --git a/Android.bp b/Android.bp
index 010a133..d201a67 100644
--- a/Android.bp
+++ b/Android.bp
@@ -44,6 +44,7 @@
         "TransportArch.cpp",
         "VintfObject.cpp",
         "XmlFile.cpp",
+        "utils-common.cpp",
     ],
     shared_libs: [
         "libbase",
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 9f3a176..c68de41 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -27,10 +27,6 @@
 #include <memory>
 #include <mutex>
 
-#ifdef LIBVINTF_TARGET
-#include <android-base/properties.h>
-#endif
-
 #include <android-base/logging.h>
 
 using std::placeholders::_1;
@@ -128,15 +124,12 @@
     }
 
     // TODO(b/70628538): Do not infer from Shipping API level.
-#ifdef LIBVINTF_TARGET
     if (deviceLevel == Level::UNSPECIFIED) {
-        auto shippingApi =
-            android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0u);
+        auto shippingApi = getPropertyFetcher().getUintProperty("ro.product.first_api_level", 0u);
         if (shippingApi != 0u) {
             deviceLevel = details::convertFromApiLevel(shippingApi);
         }
     }
-#endif
 
     if (deviceLevel == Level::UNSPECIFIED) {
         // Cannot infer FCM version. Combine all matrices by assuming
@@ -215,9 +208,8 @@
 status_t VintfObject::FetchOdmHalManifest(HalManifest* out, std::string* error) {
     status_t status;
 
-#ifdef LIBVINTF_TARGET
     std::string productModel;
-    productModel = android::base::GetProperty("ro.boot.product.hardware.sku", "");
+    productModel = getPropertyFetcher().getProperty("ro.boot.product.hardware.sku", "");
 
     if (!productModel.empty()) {
         status =
@@ -226,14 +218,12 @@
             return status;
         }
     }
-#endif
 
     status = FetchOneHalManifest(kOdmManifest, out, error);
     if (status == OK || status != NAME_NOT_FOUND) {
         return status;
     }
 
-#ifdef LIBVINTF_TARGET
     if (!productModel.empty()) {
         status = FetchOneHalManifest(kOdmLegacyVintfDir + "manifest_" + productModel + ".xml", out,
                                      error);
@@ -241,7 +231,6 @@
             return status;
         }
     }
-#endif
 
     status = FetchOneHalManifest(kOdmLegacyManifest, out, error);
     if (status == OK || status != NAME_NOT_FOUND) {
diff --git a/VintfObjectRecovery.cpp b/VintfObjectRecovery.cpp
index 59fe6da..9d7cab7 100644
--- a/VintfObjectRecovery.cpp
+++ b/VintfObjectRecovery.cpp
@@ -16,7 +16,6 @@
 
 #include "VintfObjectRecovery.h"
 
-#include <android-base/properties.h>
 #include <sys/mount.h>
 #include <fs_mgr.h>
 
@@ -48,7 +47,7 @@
         if (fstab == NULL) {
             return UNKNOWN_ERROR;
         }
-        if (android::base::GetBoolProperty("ro.build.system_root_image", false)) {
+        if (getPropertyFetcher().getBoolProperty("ro.build.system_root_image", false)) {
             return mountAt(fstab, "/", "/system_root");
         } else {
             return mountAt(fstab, "/system", "/system");
@@ -64,7 +63,7 @@
     }
 
     status_t umountSystem() const override {
-        if (android::base::GetBoolProperty("ro.build.system_root_image", false)) {
+        if (getPropertyFetcher().getBoolProperty("ro.build.system_root_image", false)) {
             return umount("/system_root");
         } else {
             return umount("/system");
diff --git a/test/utils-fake.cpp b/test/utils-fake.cpp
index 151b3bf..38f6ab0 100644
--- a/test/utils-fake.cpp
+++ b/test/utils-fake.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "utils.h"
+#include "utils-fake.h"
 
 namespace android {
 namespace vintf {
@@ -28,6 +28,18 @@
 
 ObjectFactory<RuntimeInfo>* gRuntimeInfoFactory = nullptr;
 
+MockPropertyFetcher::MockPropertyFetcher() {
+    using namespace ::testing;
+    using namespace std::placeholders;
+    ON_CALL(*this, getProperty(_, _))
+        .WillByDefault(Invoke(std::bind(&PropertyFetcher::getProperty, real_, _1, _2)));
+}
+
+MockPropertyFetcher* gPropertyFetcher = nullptr;
+const PropertyFetcher& getPropertyFetcher() {
+    return *gPropertyFetcher;
+}
+
 }  // namespace details
 }  // namespace vintf
 }  // namespace android
diff --git a/test/utils-fake.h b/test/utils-fake.h
index ec0f1df..0253bca 100644
--- a/test/utils-fake.h
+++ b/test/utils-fake.h
@@ -112,6 +112,16 @@
     std::shared_ptr<MockRuntimeInfo> object_;
 };
 
+class MockPropertyFetcher : public PropertyFetcher {
+   public:
+    MockPropertyFetcher();
+    MOCK_CONST_METHOD2(getProperty, std::string(const std::string&, const std::string&));
+
+   private:
+    PropertyFetcher real_;
+};
+extern MockPropertyFetcher* gPropertyFetcher;
+
 }  // namespace details
 }  // namespace vintf
 }  // namespace android
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index 3d834eb..d2f62d1 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -21,10 +21,6 @@
 #include <stdio.h>
 #include <unistd.h>
 
-#ifdef LIBVINTF_TARGET
-#include <android-base/properties.h>
-#endif
-
 #include <android-base/strings.h>
 #include <vintf/VintfObject.h>
 #include <vintf/parse_string.h>
@@ -290,9 +286,9 @@
 class VintfObjectTestBase : public testing::Test {
    protected:
     virtual void SetUp() {
-#ifdef LIBVINTF_TARGET
-        productModel = android::base::GetProperty("ro.boot.product.hardware.sku", "");
-#endif
+        productModel = "fake_sku";
+        ON_CALL(*gPropertyFetcher, getProperty("ro.boot.product.hardware.sku", _))
+            .WillByDefault(Return(productModel));
     }
     virtual void TearDown() {
         Mock::VerifyAndClear(&mounter());
@@ -724,7 +720,6 @@
 
 class DeviceManifestTest : public VintfObjectTestBase {
    protected:
-    virtual void SetUp() override {}
 
     // Expect that /vendor/etc/vintf/manifest.xml is fetched.
     void expectVendorManifest() { expectFetch(kVendorManifest, vendorEtcManifest); }
@@ -986,5 +981,8 @@
         std::make_shared<NiceMock<MockRuntimeInfo>>());
     gRuntimeInfoFactory = &runtimeInfoFactory;
 
+    NiceMock<MockPropertyFetcher> properties;
+    gPropertyFetcher = &properties;
+
     return RUN_ALL_TESTS();
 }
diff --git a/utils-common.cpp b/utils-common.cpp
new file mode 100644
index 0000000..3e7e736
--- /dev/null
+++ b/utils-common.cpp
@@ -0,0 +1,42 @@
+
+/*
+ * Copyright (C) 2017 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 "utils.h"
+
+// Default implementations for classes defined in utils.h
+
+namespace android {
+namespace vintf {
+namespace details {
+
+std::string PropertyFetcher::getProperty(const std::string&,
+                                         const std::string& defaultValue) const {
+    return defaultValue;
+}
+
+uint64_t PropertyFetcher::getUintProperty(const std::string&, uint64_t,
+                                          uint64_t defaultValue) const {
+    return defaultValue;
+}
+
+bool PropertyFetcher::getBoolProperty(const std::string&, bool defaultValue) const {
+    return defaultValue;
+}
+
+}  // namespace details
+}  // namespace vintf
+}  // namespace android
diff --git a/utils.cpp b/utils.cpp
index 2b0cb37..5b2bb7d 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -16,6 +16,10 @@
 
 #include "utils.h"
 
+#ifdef LIBVINTF_TARGET
+#include <android-base/properties.h>
+#endif
+
 namespace android {
 namespace vintf {
 namespace details {
@@ -29,6 +33,32 @@
 static ObjectFactory<RuntimeInfo> runtimeInfoFactory;
 ObjectFactory<RuntimeInfo>* gRuntimeInfoFactory = &runtimeInfoFactory;
 
+#ifdef LIBVINTF_TARGET
+class DevicePropertyFetcher : public PropertyFetcher {
+   public:
+    std::string getProperty(const std::string& key,
+                            const std::string& defaultValue) const override {
+        return android::base::GetProperty(key, defaultValue);
+    }
+    uint64_t getUintProperty(const std::string& key, uint64_t defaultValue,
+                             uint64_t max) const override {
+        return android::base::GetUintProperty(key, defaultValue, max);
+    }
+    bool getBoolProperty(const std::string& key, bool defaultValue) const override {
+        return android::base::GetBoolProperty(key, defaultValue);
+    }
+};
+const PropertyFetcher& getPropertyFetcher() {
+    static DevicePropertyFetcher fetcher;
+    return fetcher;
+}
+#else
+const PropertyFetcher& getPropertyFetcher() {
+    static PropertyFetcher fetcher;
+    return fetcher;
+}
+#endif
+
 }  // namespace details
 }  // namespace vintf
 }  // namespace android
diff --git a/utils.h b/utils.h
index 305a018..783d40b 100644
--- a/utils.h
+++ b/utils.h
@@ -141,6 +141,18 @@
     }
 }
 
+class PropertyFetcher {
+   public:
+    virtual ~PropertyFetcher() = default;
+    virtual std::string getProperty(const std::string& key,
+                                    const std::string& defaultValue = "") const;
+    virtual uint64_t getUintProperty(const std::string& key, uint64_t defaultValue,
+                                     uint64_t max = UINT64_MAX) const;
+    virtual bool getBoolProperty(const std::string& key, bool defaultValue) const;
+};
+
+const PropertyFetcher& getPropertyFetcher();
+
 }  // namespace details
 }  // namespace vintf
 }  // namespace android