Merge "storaged: fix divide-by-zero when updating history"
diff --git a/base/include/android-base/scopeguard.h b/base/include/android-base/scopeguard.h
index abcf4bc..c314e02 100644
--- a/base/include/android-base/scopeguard.h
+++ b/base/include/android-base/scopeguard.h
@@ -17,20 +17,27 @@
 #ifndef ANDROID_BASE_SCOPEGUARD_H
 #define ANDROID_BASE_SCOPEGUARD_H
 
-#include <utility>  // for std::move
+#include <utility>  // for std::move, std::forward
 
 namespace android {
 namespace base {
 
+// ScopeGuard ensures that the specified functor is executed no matter how the
+// current scope exits.
 template <typename F>
 class ScopeGuard {
  public:
-  ScopeGuard(F f) : f_(f), active_(true) {}
+  ScopeGuard(F&& f) : f_(std::forward<F>(f)), active_(true) {}
 
   ScopeGuard(ScopeGuard&& that) : f_(std::move(that.f_)), active_(that.active_) {
     that.active_ = false;
   }
 
+  template <typename Functor>
+  ScopeGuard(ScopeGuard<Functor>&& that) : f_(std::move(that.f_)), active_(that.active_) {
+    that.active_ = false;
+  }
+
   ~ScopeGuard() {
     if (active_) f_();
   }
@@ -45,13 +52,16 @@
   bool active() const { return active_; }
 
  private:
+  template <typename Functor>
+  friend class ScopeGuard;
+
   F f_;
   bool active_;
 };
 
-template <typename T>
-ScopeGuard<T> make_scope_guard(T f) {
-  return ScopeGuard<T>(f);
+template <typename F>
+ScopeGuard<F> make_scope_guard(F&& f) {
+  return ScopeGuard<F>(std::forward<F>(f));
 }
 
 }  // namespace base
diff --git a/base/scopeguard_test.cpp b/base/scopeguard_test.cpp
index e11154a..9236d7b 100644
--- a/base/scopeguard_test.cpp
+++ b/base/scopeguard_test.cpp
@@ -17,6 +17,7 @@
 #include "android-base/scopeguard.h"
 
 #include <utility>
+#include <vector>
 
 #include <gtest/gtest.h>
 
@@ -44,3 +45,15 @@
   EXPECT_FALSE(scopeguard.active());
   ASSERT_FALSE(guarded_var);
 }
+
+TEST(scopeguard, vector) {
+  int guarded_var = 0;
+  {
+    std::vector<android::base::ScopeGuard<std::function<void()>>> scopeguards;
+    scopeguards.emplace_back(android::base::make_scope_guard(
+        std::bind([](int& guarded_var) { guarded_var++; }, std::ref(guarded_var))));
+    scopeguards.emplace_back(android::base::make_scope_guard(
+        std::bind([](int& guarded_var) { guarded_var++; }, std::ref(guarded_var))));
+  }
+  ASSERT_EQ(guarded_var, 2);
+}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 536d64e..6b01aae 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -123,6 +123,7 @@
     { nullptr,    "boot_other.img",   "boot.sig",     "boot",     true,  true  },
     { "dtbo",     "dtbo.img",         "dtbo.sig",     "dtbo",     true,  false },
     { "dts",      "dt.img",           "dt.sig",       "dts",      true,  false },
+    { "product",  "product.img",      "product.sig",  "product",  true,  false },
     { "recovery", "recovery.img",     "recovery.sig", "recovery", true,  false },
     { "system",   "system.img",       "system.sig",   "system",   false, false },
     { nullptr,    "system_other.img", "system.sig",   "system",   true,  true  },
diff --git a/property_service/property_info_checker/Android.bp b/property_service/property_info_checker/Android.bp
index 6ee649a..7d66199 100644
--- a/property_service/property_info_checker/Android.bp
+++ b/property_service/property_info_checker/Android.bp
@@ -7,6 +7,7 @@
         "libpropertyinfoserializer",
         "libpropertyinfoparser",
         "libbase",
+        "libsepol",
     ],
     srcs: ["property_info_checker.cpp"],
 }
diff --git a/property_service/property_info_checker/property_info_checker.cpp b/property_service/property_info_checker/property_info_checker.cpp
index e4f8264..52c4383 100644
--- a/property_service/property_info_checker/property_info_checker.cpp
+++ b/property_service/property_info_checker/property_info_checker.cpp
@@ -1,26 +1,150 @@
 #include <iostream>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include <android-base/file.h>
-
+#include <property_info_parser/property_info_parser.h>
 #include <property_info_serializer/property_info_serializer.h>
+#include <sepol/context.h>
+#include <sepol/context_record.h>
+#include <sepol/handle.h>
+#include <sepol/policydb.h>
+#include <sepol/policydb/policydb.h>
 
 using android::base::ReadFileToString;
 using android::properties::BuildTrie;
 using android::properties::ParsePropertyInfoFile;
+using android::properties::PropertyInfoArea;
 using android::properties::PropertyInfoEntry;
 
+class ContextChecker {
+ public:
+  ContextChecker()
+      : policy_file_(nullptr),
+        sepol_handle_(nullptr),
+        sepol_policy_file_(nullptr),
+        sepol_policy_db_(nullptr) {}
+
+  ~ContextChecker() {
+    if (sepol_policy_db_ != nullptr) {
+      sepol_policydb_free(sepol_policy_db_);
+    }
+
+    if (sepol_policy_file_ != nullptr) {
+      sepol_policy_file_free(sepol_policy_file_);
+    }
+
+    if (sepol_handle_ != nullptr) {
+      sepol_handle_destroy(sepol_handle_);
+    }
+
+    if (policy_file_ != nullptr) {
+      fclose(policy_file_);
+    }
+  }
+
+  bool Initialize(const char* policy_file) {
+    policy_file_ = fopen(policy_file, "re");
+    if (policy_file_ == nullptr) {
+      std::cerr << "Could not open policy file, " << policy_file << std::endl;
+      return false;
+    }
+
+    sepol_handle_ = sepol_handle_create();
+    if (sepol_handle_ == nullptr) {
+      std::cerr << "Could not create policy handle." << std::endl;
+      return false;
+    }
+
+    if (sepol_policy_file_create(&sepol_policy_file_) < 0) {
+      std::cerr << "Could not create policy file." << std::endl;
+      return false;
+    }
+
+    if (sepol_policydb_create(&sepol_policy_db_) < 0) {
+      std::cerr << "Could not create policy db." << std::endl;
+      return false;
+    }
+
+    sepol_policy_file_set_fp(sepol_policy_file_, policy_file_);
+    sepol_policy_file_set_handle(sepol_policy_file_, sepol_handle_);
+
+    if (sepol_policydb_read(sepol_policy_db_, sepol_policy_file_) < 0) {
+      std::cerr << "Could not read policy file into policy db." << std::endl;
+      return false;
+    }
+
+    auto* attr =
+        reinterpret_cast<type_datum*>(hashtab_search(policy_db_->p_types.table, "property_type"));
+    if (attr == nullptr || attr->flavor != TYPE_ATTRIB) {
+      std::cerr << "'property_type' is not defined correctly." << std::endl;
+      return false;
+    }
+
+    property_type_bit_ = attr->s.value - 1;
+
+    return true;
+  }
+
+  bool CheckContext(const char* context) {
+    sepol_context_t* sepol_context_raw;
+    if (sepol_context_from_string(sepol_handle_, context, &sepol_context_raw) < 0) {
+      std::cerr << "Could not allocate context for " << context << std::endl;
+      return false;
+    }
+    auto sepol_context = std::unique_ptr<sepol_context_t, decltype(&sepol_context_free)>{
+        sepol_context_raw, sepol_context_free};
+
+    if (sepol_context_check(sepol_handle_, sepol_policy_db_, sepol_context.get()) < 0) {
+      std::cerr << "Sepol context check failed for " << context << std::endl;
+      return false;
+    }
+
+    const char* context_type = sepol_context_get_type(sepol_context.get());
+
+    auto* type =
+        reinterpret_cast<type_datum*>(hashtab_search(policy_db_->p_types.table, context_type));
+    if (type == nullptr) {
+      std::cerr << "Could not find context '" << context << "' in policy database" << std::endl;
+      return false;
+    }
+
+    if (type->flavor != TYPE_TYPE) {
+      std::cerr << "Context '" << context << "' is not defined as a type in policy database"
+                << std::endl;
+      return false;
+    }
+
+    if (!ebitmap_get_bit(&policy_db_->type_attr_map[type->s.value - 1], property_type_bit_)) {
+      std::cerr << "Context '" << context << "' does not have property_type attribute" << std::endl;
+      return false;
+    }
+
+    return true;
+  }
+
+ private:
+  FILE* policy_file_;
+  sepol_handle_t* sepol_handle_;
+  sepol_policy_file_t* sepol_policy_file_;
+  union {
+    sepol_policydb_t* sepol_policy_db_;
+    policydb_t* policy_db_;
+  };
+  unsigned int property_type_bit_;
+};
+
 int main(int argc, char** argv) {
-  if (argc < 2) {
-    std::cerr << "A list of property info files to be checked is expected on the command line"
-              << std::endl;
+  if (argc < 3) {
+    std::cerr << "usage: " << argv[0]
+              << " COMPILED_SEPOLICY PROPERTY_INFO_FILE [PROPERTY_INFO_FILE]..." << std::endl;
     return -1;
   }
 
   auto property_info_entries = std::vector<PropertyInfoEntry>{};
 
-  for (int i = 1; i < argc; ++i) {
+  for (int i = 2; i < argc; ++i) {
     auto filename = argv[i];
     auto file_contents = std::string{};
     if (!ReadFileToString(filename, &file_contents)) {
@@ -47,5 +171,17 @@
     return -1;
   }
 
+  auto checker = ContextChecker{};
+  if (!checker.Initialize(argv[1])) {
+    return -1;
+  }
+
+  auto property_info_area = reinterpret_cast<PropertyInfoArea*>(serialized_contexts.data());
+  for (size_t i = 0; i < property_info_area->num_contexts(); ++i) {
+    if (!checker.CheckContext(property_info_area->context(i))) {
+      return -1;
+    }
+  }
+
   return 0;
 }
diff --git a/rootdir/init.usb.configfs.rc b/rootdir/init.usb.configfs.rc
index de1aab3..3a33c94 100644
--- a/rootdir/init.usb.configfs.rc
+++ b/rootdir/init.usb.configfs.rc
@@ -2,7 +2,6 @@
     write /config/usb_gadget/g1/UDC "none"
     stop adbd
     setprop sys.usb.ffs.ready 0
-    setprop sys.usb.ffs.mtp.ready 0
     write /config/usb_gadget/g1/bDeviceClass 0
     write /config/usb_gadget/g1/bDeviceSubClass 0
     write /config/usb_gadget/g1/bDeviceProtocol 0
@@ -24,7 +23,7 @@
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
 
-on property:sys.usb.ffs.mtp.ready=1 && property:sys.usb.config=mtp && property:sys.usb.configfs=1
+on property:sys.usb.config=mtp && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp"
     symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -33,15 +32,14 @@
 on property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
     start adbd
 
-on property:sys.usb.ffs.ready=1 && property:sys.usb.ffs.mtp.ready=1 && \
-property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp_adb"
     symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
     setprop sys.usb.state ${sys.usb.config}
 
-on property:sys.usb.ffs.mtp.ready=1 && property:sys.usb.config=ptp && property:sys.usb.configfs=1
+on property:sys.usb.config=ptp && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp"
     symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1
     write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -50,8 +48,7 @@
 on property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
     start adbd
 
-on property:sys.usb.ffs.ready=1 && property:sys.usb.ffs.mtp.ready=1 && \
-property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
+on property:sys.usb.ffs.ready=1 && property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
     write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp_adb"
     symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1
     symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2