Merge "Refactor module registration"
diff --git a/nfc/V1_0/host/VtsHalNfcV1_0HostTest.py b/nfc/V1_0/host/VtsHalNfcV1_0HostTest.py
index 9976660..03f195d 100644
--- a/nfc/V1_0/host/VtsHalNfcV1_0HostTest.py
+++ b/nfc/V1_0/host/VtsHalNfcV1_0HostTest.py
@@ -63,7 +63,7 @@
 
         if self.coverage.enabled:
             self.coverage.LoadArtifacts()
-            self.coverage.InitializeDeviceCoverage(self._dut)
+            self.coverage.InitializeDeviceCoverage(self.dut)
 
     def tearDownClass(self):
         """Turns off the framework-layer NFC service."""
diff --git a/treble/platform_version/VtsTreblePlatformVersionTest.py b/treble/platform_version/VtsTreblePlatformVersionTest.py
index 4441897..a5e6728 100644
--- a/treble/platform_version/VtsTreblePlatformVersionTest.py
+++ b/treble/platform_version/VtsTreblePlatformVersionTest.py
@@ -32,21 +32,58 @@
         self.dut = self.registerController(android_device)[0]
         self.dut.shell.InvokeTerminal("VtsTreblePlatformVersionTest")
 
-    def testPlatformVersion(self):
-        """Test that device launched with O or later."""
+    def getProp(self, prop, required=True):
+        """Helper to retrieve a property from device."""
 
         results = self.dut.shell.VtsTreblePlatformVersionTest.Execute(
-            "getprop ro.product.first_api_level")
-        asserts.assertEqual(results[const.EXIT_CODE][0], 0,
-            "getprop must succeed")
+            "getprop " + prop)
+        if required:
+            asserts.assertEqual(results[const.EXIT_CODE][0], 0,
+                "getprop must succeed")
+        else:
+            if results[const.EXIT_CODE][0] != 0:
+                logging.info("sysprop %s undefined", prop)
+                return None
 
+        result = results[const.STDOUT][0].strip()
+
+        logging.info("getprop {}={}".format(prop, result))
+
+        return result
+
+    def testFirstApiLevel(self):
+        """Test that device launched with O or later."""
         try:
-            firstApiLevel = int(results[const.STDOUT][0].strip())
-            logging.info("Device first API level is {}".format(firstApiLevel))
+            firstApiLevel = self.getProp("ro.product.first_api_level",
+                                         required=False)
+            if firstApiLevel is None:
+                asserts.skip("ro.product.first_api_level undefined")
+            firstApiLevel = int(firstApiLevel)
             asserts.assertTrue(firstApiLevel >= ANDROID_O_API_VERSION,
                 "VTS can only be run for new launches in O or above")
         except ValueError:
             asserts.fail("Unexpected value returned from getprop")
 
+    def testTrebleEnabled(self):
+        """Test that device has Treble enabled."""
+        trebleIsEnabledStr = self.getProp("ro.treble.enabled")
+        asserts.assertEqual(trebleIsEnabledStr, "true",
+            "VTS can only be run for Treble enabled devices")
+
+    def testSdkVersion(self):
+        """Test that SDK version >= O (26)."""
+        try:
+            sdkVersion = int(self.getProp("ro.build.version.sdk"))
+            asserts.assertTrue(sdkVersion >= ANDROID_O_API_VERSION,
+                "VTS is for devices launching in O or above")
+        except ValueError:
+            asserts.fail("Unexpected value returned from getprop")
+
+    def testVndkVersion(self):
+        """Test that VNDK version is specified."""
+        vndkVersion = self.getProp("ro.vendor.vndk.version")
+        asserts.assertLess(0, len(vndkVersion),
+            "VNDK version is not defined")
+
 if __name__ == "__main__":
     test_runner.main()
diff --git a/treble/vintf/vts_treble_vintf_test.cpp b/treble/vintf/vts_treble_vintf_test.cpp
index e8f5251..45c2681 100644
--- a/treble/vintf/vts_treble_vintf_test.cpp
+++ b/treble/vintf/vts_treble_vintf_test.cpp
@@ -73,7 +73,7 @@
 // For a given interface returns package root if known. Returns empty string
 // otherwise.
 static const string PackageRoot(const FQName &fq_iface_name) {
-  for (const auto &package_root: kPackageRoot) {
+  for (const auto &package_root : kPackageRoot) {
     if (fq_iface_name.inPackage(package_root.first)) {
       return package_root.second;
     }
@@ -87,6 +87,19 @@
   return !PackageRoot(fq_iface_name).empty();
 }
 
+// Returns true iff HAL interface is exempt from following rules:
+// 1. If an interface is declared in VINTF, it has to be served on the device.
+// TODO(b/62547028): remove these exemptions in O-DR.
+static bool IsExempt(const FQName &fq_iface_name) {
+  static const set<string> exempt_hals_ = {
+      "android.hardware.radio", "android.hardware.radio.deprecated",
+  };
+  string hal_name = fq_iface_name.package();
+  // Radio-releated and non-Google HAL interfaces are given exemptions.
+  return exempt_hals_.find(hal_name) != exempt_hals_.end() ||
+         !IsGoogleDefinedIface(fq_iface_name);
+}
+
 // Returns the set of released hashes for a given HAL interface.
 static set<string> ReleasedHashes(const FQName &fq_iface_name) {
   set<string> released_hashes{};
@@ -221,6 +234,11 @@
   // Verifies that HAL is available through service manager.
   HalVerifyFn is_available = [this](const FQName &fq_name,
                                     const string &instance_name) {
+    if (IsExempt(fq_name)) {
+      cout << fq_name.string() << " is exempt." << endl;
+      return;
+    }
+
     sp<android::hidl::base::V1_0::IBase> hal_service =
         GetHalService(fq_name, instance_name);
     EXPECT_NE(hal_service, nullptr)
@@ -239,6 +257,15 @@
     sp<android::hidl::base::V1_0::IBase> hal_service =
         GetHalService(fq_name, instance_name);
 
+    if (hal_service == nullptr) {
+      if (IsExempt(fq_name)) {
+        cout << fq_name.string() << " is exempt." << endl;
+      } else {
+        ADD_FAILURE() << fq_name.package() << " not available." << endl;
+      }
+      return;
+    }
+
     vector<string> iface_chain{};
     hal_service->interfaceChain(
         [&iface_chain](const hidl_vec<hidl_string> &chain) {