Merge "stats: Set min_sdk_version" into rvc-dev
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index f6c2b5a..976cd90 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -68,6 +68,7 @@
         "libdm",
         "libfs_mgr",
         "liblog",
+        "libgsi",
     ],
 
     data: [
diff --git a/fs_mgr/libfiemap/fiemap_writer_test.cpp b/fs_mgr/libfiemap/fiemap_writer_test.cpp
index 22a3722..3c8ab42 100644
--- a/fs_mgr/libfiemap/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap/fiemap_writer_test.cpp
@@ -35,6 +35,7 @@
 #include <libdm/loop_control.h>
 #include <libfiemap/fiemap_writer.h>
 #include <libfiemap/split_fiemap_writer.h>
+#include <libgsi/libgsi.h>
 
 #include "utility.h"
 
@@ -148,7 +149,10 @@
     FiemapUniquePtr fptr = FiemapWriter::Open(testfile, gBlockSize);
     EXPECT_EQ(fptr->size(), gBlockSize);
     EXPECT_EQ(fptr->bdev_path().find("/dev/block/"), size_t(0));
-    EXPECT_EQ(fptr->bdev_path().find("/dev/block/dm-"), string::npos);
+
+    if (!android::gsi::IsGsiRunning()) {
+        EXPECT_EQ(fptr->bdev_path().find("/dev/block/dm-"), string::npos);
+    }
 }
 
 TEST_F(FiemapWriterTest, CheckFileCreated) {
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp
index efdb59f..0df5664 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp
@@ -181,6 +181,13 @@
     ret.snapshot_status.set_device_size(target_partition->size());
     ret.snapshot_status.set_snapshot_size(target_partition->size());
 
+    if (ret.snapshot_status.snapshot_size() == 0) {
+        LOG(INFO) << "Not creating snapshot for partition " << ret.snapshot_status.name();
+        ret.snapshot_status.set_cow_partition_size(0);
+        ret.snapshot_status.set_cow_file_size(0);
+        return ret;
+    }
+
     // Being the COW partition virtual, its size doesn't affect the storage
     // memory that will be occupied by the target.
     // The actual storage space is affected by the COW file, whose size depends
diff --git a/init/README.md b/init/README.md
index 13f1bac..726c0cc 100644
--- a/init/README.md
+++ b/init/README.md
@@ -322,6 +322,10 @@
   This is mutually exclusive with the console option, which additionally connects stdin to the
   given console.
 
+`task_profiles <profile> [ <profile>\* ]`
+> Set task profiles for the process when it forks. This is designed to replace the use of
+  writepid option for moving a process into a cgroup.
+
 `timeout_period <seconds>`
 > Provide a timeout after which point the service will be killed. The oneshot keyword is respected
   here, so oneshot services do not automatically restart, however all other services will.
@@ -356,6 +360,8 @@
   cgroup/cpuset usage. If no files under /dev/cpuset/ are specified, but the
   system property 'ro.cpuset.default' is set to a non-empty cpuset name (e.g.
   '/foreground'), then the pid is written to file /dev/cpuset/_cpuset\_name_/tasks.
+  The use of this option for moving a process into a cgroup is obsolete. Please
+  use task_profiles option instead.
 
 
 Triggers
diff --git a/init/service.cpp b/init/service.cpp
index b12d11a..69f944e 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -511,6 +511,10 @@
             LOG(ERROR) << "failed to write pid to files: " << result.error();
         }
 
+        if (task_profiles_.size() > 0 && !SetTaskProfiles(getpid(), task_profiles_)) {
+            LOG(ERROR) << "failed to set task profiles";
+        }
+
         // As requested, set our gid, supplemental gids, uid, context, and
         // priority. Aborts on failure.
         SetProcessAttributesAndCaps();
diff --git a/init/service.h b/init/service.h
index 9f1d697..34ed5ef 100644
--- a/init/service.h
+++ b/init/service.h
@@ -170,6 +170,8 @@
 
     std::vector<std::string> writepid_files_;
 
+    std::vector<std::string> task_profiles_;
+
     std::set<std::string> interfaces_;  // e.g. some.package.foo@1.0::IBaz/instance-name
 
     // keycodes for triggering this service via /dev/input/input*
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index c54ed71..bdac077 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -360,6 +360,12 @@
     return Error() << "Invalid shutdown option";
 }
 
+Result<void> ServiceParser::ParseTaskProfiles(std::vector<std::string>&& args) {
+    args.erase(args.begin());
+    service_->task_profiles_ = std::move(args);
+    return {};
+}
+
 Result<void> ServiceParser::ParseTimeoutPeriod(std::vector<std::string>&& args) {
     int period;
     if (!ParseInt(args[1], &period, 1)) {
@@ -529,6 +535,7 @@
         {"sigstop",                 {0,     0,    &ServiceParser::ParseSigstop}},
         {"socket",                  {3,     6,    &ServiceParser::ParseSocket}},
         {"stdio_to_kmsg",           {0,     0,    &ServiceParser::ParseStdioToKmsg}},
+        {"task_profiles",           {1,     kMax, &ServiceParser::ParseTaskProfiles}},
         {"timeout_period",          {1,     1,    &ServiceParser::ParseTimeoutPeriod}},
         {"updatable",               {0,     0,    &ServiceParser::ParseUpdatable}},
         {"user",                    {1,     1,    &ServiceParser::ParseUser}},
diff --git a/init/service_parser.h b/init/service_parser.h
index 7bb0cc0..0fd2da5 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -78,6 +78,7 @@
     Result<void> ParseSigstop(std::vector<std::string>&& args);
     Result<void> ParseSocket(std::vector<std::string>&& args);
     Result<void> ParseStdioToKmsg(std::vector<std::string>&& args);
+    Result<void> ParseTaskProfiles(std::vector<std::string>&& args);
     Result<void> ParseTimeoutPeriod(std::vector<std::string>&& args);
     Result<void> ParseFile(std::vector<std::string>&& args);
     Result<void> ParseUser(std::vector<std::string>&& args);
diff --git a/liblog/tests/logd_writer_test.cpp b/liblog/tests/logd_writer_test.cpp
index c856720..b8e4726 100644
--- a/liblog/tests/logd_writer_test.cpp
+++ b/liblog/tests/logd_writer_test.cpp
@@ -29,6 +29,10 @@
 // socket.  This tests for that behavior.
 TEST(liblog, multi_connect_dgram_socket) {
 #ifdef __ANDROID__
+  if (getuid() != 0) {
+    GTEST_SKIP() << "Skipping test, must be run as root.";
+    return;
+  }
   auto temp_dir = TemporaryDir();
   auto socket_path = StringPrintf("%s/test_socket", temp_dir.path);
 
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 0cee6bb..bc6bc7c 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -149,6 +149,19 @@
         }
       ]
     },
+    {
+      "Name": "CameraServicePerformance",
+      "Actions": [
+        {
+          "Name": "JoinCgroup",
+          "Params":
+          {
+            "Controller": "schedtune",
+            "Path": "camera-daemon"
+          }
+        }
+      ]
+    },
 
     {
       "Name": "CpuPolicySpread",
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 8f49ad9..670d904 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -159,6 +159,8 @@
         search_map_idx = old_map_idx + 1;
         if (new_map_idx + 1 < maps_.size()) {
           maps_[new_map_idx + 1]->prev_map = info.get();
+          maps_[new_map_idx + 1]->prev_real_map =
+              info->IsBlank() ? info->prev_real_map : info.get();
         }
         maps_[new_map_idx] = nullptr;
         total_entries--;
diff --git a/libunwindstack/tests/LocalUpdatableMapsTest.cpp b/libunwindstack/tests/LocalUpdatableMapsTest.cpp
index b816b9a..99afb0b 100644
--- a/libunwindstack/tests/LocalUpdatableMapsTest.cpp
+++ b/libunwindstack/tests/LocalUpdatableMapsTest.cpp
@@ -271,4 +271,103 @@
   EXPECT_TRUE(map_info->name.empty());
 }
 
+TEST_F(LocalUpdatableMapsTest, add_map_prev_name_updated) {
+  TemporaryFile tf;
+  ASSERT_TRUE(
+      android::base::WriteStringToFile("3000-4000 rwxp 00000 00:00 0\n"
+                                       "8000-9000 r-xp 00000 00:00 0\n"
+                                       "9000-a000 r-xp 00000 00:00 0\n",
+                                       tf.path));
+
+  maps_.TestSetMapsFile(tf.path);
+  ASSERT_TRUE(maps_.Reparse());
+  ASSERT_EQ(3U, maps_.Total());
+
+  MapInfo* map_info = maps_.Get(2);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0x9000U, map_info->start);
+  EXPECT_EQ(0xA000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
+  EXPECT_TRUE(map_info->name.empty());
+  EXPECT_EQ(maps_.Get(1), map_info->prev_map);
+}
+
+TEST_F(LocalUpdatableMapsTest, add_map_prev_real_name_updated) {
+  TemporaryFile tf;
+  ASSERT_TRUE(
+      android::base::WriteStringToFile("3000-4000 r-xp 00000 00:00 0 /fake/lib.so\n"
+                                       "4000-5000 ---p 00000 00:00 0\n"
+                                       "7000-8000 r-xp 00000 00:00 0 /fake/lib1.so\n"
+                                       "8000-9000 ---p 00000 00:00 0\n",
+                                       tf.path));
+
+  maps_.TestSetMapsFile(tf.path);
+  ASSERT_TRUE(maps_.Reparse());
+  ASSERT_EQ(4U, maps_.Total());
+
+  MapInfo* map_info = maps_.Get(2);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0x7000U, map_info->start);
+  EXPECT_EQ(0x8000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
+  EXPECT_EQ(maps_.Get(0), map_info->prev_real_map);
+  EXPECT_EQ(maps_.Get(1), map_info->prev_map);
+  EXPECT_EQ("/fake/lib1.so", map_info->name);
+
+  map_info = maps_.Get(3);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0x8000U, map_info->start);
+  EXPECT_EQ(0x9000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_TRUE(map_info->IsBlank());
+  EXPECT_EQ(maps_.Get(2), map_info->prev_real_map);
+  EXPECT_EQ(maps_.Get(2), map_info->prev_map);
+  EXPECT_TRUE(map_info->name.empty());
+
+  ASSERT_TRUE(
+      android::base::WriteStringToFile("3000-4000 r-xp 00000 00:00 0 /fake/lib.so\n"
+                                       "4000-5000 ---p 00000 00:00 0\n"
+                                       "7000-8000 r-xp 00000 00:00 0 /fake/lib1.so\n"
+                                       "8000-9000 ---p 00000 00:00 0\n"
+                                       "9000-a000 r-xp 00000 00:00 0 /fake/lib2.so\n"
+                                       "a000-b000 r-xp 00000 00:00 0 /fake/lib3.so\n",
+                                       tf.path));
+
+  maps_.TestSetMapsFile(tf.path);
+  ASSERT_TRUE(maps_.Reparse());
+  ASSERT_EQ(6U, maps_.Total());
+
+  map_info = maps_.Get(2);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0x7000U, map_info->start);
+  EXPECT_EQ(0x8000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
+  EXPECT_EQ("/fake/lib1.so", map_info->name);
+  EXPECT_EQ(maps_.Get(1), map_info->prev_map);
+  EXPECT_EQ(maps_.Get(0), map_info->prev_real_map);
+
+  map_info = maps_.Get(4);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0x9000U, map_info->start);
+  EXPECT_EQ(0xA000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
+  EXPECT_EQ("/fake/lib2.so", map_info->name);
+  EXPECT_EQ(maps_.Get(3), map_info->prev_map);
+  EXPECT_EQ(maps_.Get(2), map_info->prev_real_map);
+
+  map_info = maps_.Get(5);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_EQ(0xA000U, map_info->start);
+  EXPECT_EQ(0xB000U, map_info->end);
+  EXPECT_EQ(0U, map_info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
+  EXPECT_EQ("/fake/lib3.so", map_info->name);
+  EXPECT_EQ(maps_.Get(4), map_info->prev_map);
+  EXPECT_EQ(maps_.Get(4), map_info->prev_real_map);
+}
+
 }  // namespace unwindstack