Merge "llkd: adbd is allowed to be a bad parent on userdebug"
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 079a975..054cbac 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -331,11 +331,6 @@
         error_exit("Attempting to use streaming install on unsupported device");
     }
 
-    if (use_fastdeploy == true && is_reinstall == false) {
-        printf("Fast Deploy is only available with -r.\n");
-        use_fastdeploy = false;
-    }
-
     if (use_fastdeploy == true && get_device_api_level() < kFastDeployMinApi) {
         printf("Fast Deploy is only compatible with devices of API version %d or higher, "
                "ignoring.\n",
@@ -350,10 +345,17 @@
             passthrough_argv.push_back(argv[i]);
         }
     }
+    if (passthrough_argv.size() < 2) {
+        error_exit("install requires an apk argument");
+    }
 
     if (use_fastdeploy == true) {
         fastdeploy_set_local_agent(use_localagent);
         update_agent(agent_update_strategy);
+
+        // The last argument must be the APK file
+        const char* file = passthrough_argv.back();
+        use_fastdeploy = find_package(file);
     }
 
     switch (installMode) {
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index c8e834e..8676214 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -154,8 +154,8 @@
         "     --instant: cause the app to be installed as an ephemeral install app\n"
         "     --no-streaming: always push APK to device and invoke Package Manager as separate steps\n"
         "     --streaming: force streaming APK directly into Package Manager\n"
-        "     --fastdeploy: use fast deploy (only valid with -r)\n"
-        "     --no-fastdeploy: prevent use of fast deploy (only valid with -r)\n"
+        "     --fastdeploy: use fast deploy\n"
+        "     --no-fastdeploy: prevent use of fast deploy\n"
         "     --force-agent: force update of deployment agent when using fast deploy\n"
         "     --date-check-agent: update deployment agent when local version is newer and using fast deploy\n"
         "     --version-check-agent: update deployment agent when local version has different version code and using fast deploy\n"
diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp
index e82f15a..f4e8664 100644
--- a/adb/client/fastdeploy.cpp
+++ b/adb/client/fastdeploy.cpp
@@ -16,6 +16,7 @@
 
 #include "fastdeploy.h"
 
+#include <string.h>
 #include <algorithm>
 #include <array>
 #include <memory>
@@ -31,7 +32,7 @@
 
 #include "adb_utils.h"
 
-static constexpr long kRequiredAgentVersion = 0x00000001;
+static constexpr long kRequiredAgentVersion = 0x00000002;
 
 static constexpr const char* kDeviceAgentPath = "/data/local/tmp/";
 
@@ -313,9 +314,16 @@
     std::vector<unsigned char> applyErrorBuffer;
     std::string argsString;
 
+    bool rSwitchPresent = false;
     for (int i = 0; i < argc; i++) {
         argsString.append(argv[i]);
         argsString.append(" ");
+        if (!strcmp(argv[i], "-r")) {
+            rSwitchPresent = true;
+        }
+    }
+    if (!rSwitchPresent) {
+        argsString.append("-r");
     }
 
     std::string applyPatchCommand =
@@ -326,3 +334,9 @@
         error_exit("Executing %s returned %d", applyPatchCommand.c_str(), returnCode);
     }
 }
+
+bool find_package(const char* apkPath) {
+    const std::string findCommand =
+            "/data/local/tmp/deployagent find " + get_packagename_from_apk(apkPath);
+    return !send_shell_command(findCommand);
+}
diff --git a/adb/client/fastdeploy.h b/adb/client/fastdeploy.h
index a6b10d3..7b7f2ec 100644
--- a/adb/client/fastdeploy.h
+++ b/adb/client/fastdeploy.h
@@ -32,3 +32,4 @@
 void apply_patch_on_device(const char* apkPath, const char* patchPath, const char* outputPath);
 void install_patch(const char* apkPath, const char* patchPath, int argc, const char** argv);
 std::string get_patch_path(const char* apkPath);
+bool find_package(const char* apkPath);
diff --git a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java b/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java
index 17845e2..2d3b135 100644
--- a/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java
+++ b/adb/fastdeploy/deployagent/src/com/android/fastdeploy/DeployAgent.java
@@ -35,7 +35,7 @@
 
 public final class DeployAgent {
     private static final int BUFFER_SIZE = 128 * 1024;
-    private static final int AGENT_VERSION = 0x00000001;
+    private static final int AGENT_VERSION = 0x00000002;
 
     public static void main(String[] args) {
         int exitCode = 0;
@@ -53,6 +53,15 @@
 
                 String packageName = args[1];
                 extractMetaData(packageName);
+            } else if (commandString.equals("find")) {
+                if (args.length != 2) {
+                    showUsage(1);
+                }
+
+                String packageName = args[1];
+                if (getFilenameFromPackageName(packageName) == null) {
+                    exitCode = 3;
+                }
             } else if (commandString.equals("apply")) {
                 if (args.length < 4) {
                     showUsage(1);
@@ -112,6 +121,7 @@
             "usage: deployagent <command> [<args>]\n\n" +
             "commands:\n" +
             "version                             get the version\n" +
+            "find PKGNAME                        return zero if package found, else non-zero\n" +
             "extract PKGNAME                     extract an installed package's metadata\n" +
             "apply PKGNAME PATCHFILE [-o|-pm]    apply a patch from PATCHFILE (- for stdin) to an installed package\n" +
             " -o <FILE> directs output to FILE, default or - for stdout\n" +
@@ -134,7 +144,7 @@
         return null;
     }
 
-    private static File getFileFromPackageName(String packageName) throws IOException {
+    private static String getFilenameFromPackageName(String packageName) throws IOException {
         StringBuilder commandBuilder = new StringBuilder();
         commandBuilder.append("pm list packages -f " + packageName);
 
@@ -153,10 +163,19 @@
                 int equalsIndex = line.lastIndexOf(packageSuffix);
                 String fileName =
                     line.substring(packageIndex + packagePrefix.length(), equalsIndex);
-                return new File(fileName);
+                return fileName;
             }
         }
-        throw new IOException("package not found");
+        return null;
+    }
+
+    private static File getFileFromPackageName(String packageName) throws IOException {
+        String filename = getFilenameFromPackageName(packageName);
+        if (filename == null) {
+            // Should not happen (function is only called when we know the package exists)
+            throw new IOException("package not found");
+        }
+        return new File(filename);
     }
 
     private static void extractMetaData(String packageName) throws IOException {
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 421ce43..d24c887 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <stdlib.h>
+#include <time.h>
 
 #include <memory>
 #include <string>
@@ -494,3 +495,10 @@
   expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
   ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
 }
+
+TEST_F(TombstoneTest, dump_timestamp) {
+  setenv("TZ", "UTC", 1);
+  tzset();
+  dump_timestamp(&log_, 0);
+  ASSERT_STREQ("Timestamp: 1970-01-01 00:00:00+0000\n", amfd_data_.c_str());
+}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 1179263..b20014f 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -78,6 +78,15 @@
   _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
 }
 
+static void dump_timestamp(log_t* log, time_t time) {
+  struct tm tm;
+  localtime_r(&time, &tm);
+
+  char buf[strlen("1970-01-01 00:00:00+0830") + 1];
+  strftime(buf, sizeof(buf), "%F %T%z", &tm);
+  _LOG(log, logtype::HEADER, "Timestamp: %s\n", buf);
+}
+
 static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* map) {
   std::string cause;
   if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
@@ -654,6 +663,7 @@
 
   _LOG(&log, logtype::HEADER, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
   dump_header_info(&log);
+  dump_timestamp(&log, time(nullptr));
 
   auto it = threads.find(target_thread);
   if (it == threads.end()) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 8757689..88f7a2c 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -615,7 +615,7 @@
 // Sets errno to match the 1st mount failure on failure.
 static bool mount_with_alternatives(const Fstab& fstab, int start_idx, int* end_idx,
                                     int* attempted_idx) {
-    int i;
+    unsigned long i;
     int mount_errno = 0;
     bool mounted = false;
 
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index d3cd459..e0891eb 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -59,7 +59,7 @@
 
 struct flag_list {
     const char *name;
-    unsigned int flag;
+    uint64_t flag;
 };
 
 static struct flag_list mount_flags[] = {
@@ -116,6 +116,7 @@
         {"logical", MF_LOGICAL},
         {"checkpoint=block", MF_CHECKPOINT_BLK},
         {"checkpoint=fs", MF_CHECKPOINT_FS},
+        {"slotselect_other", MF_SLOTSELECT_OTHER},
         {0, 0},
 };
 
@@ -153,7 +154,7 @@
     return 0;
 }
 
-static const char* flag_to_encryption_mode(const struct flag_list* list, int flag) {
+static const char* flag_to_encryption_mode(const struct flag_list* list, uint64_t flag) {
     const struct flag_list *j;
 
     for (j = list; j->name; ++j) {
@@ -207,11 +208,9 @@
     return false;
 }
 
-static int parse_flags(char *flags, struct flag_list *fl,
-                       struct fs_mgr_flag_values *flag_vals,
-                       char *fs_options, int fs_options_len)
-{
-    int f = 0;
+static uint64_t parse_flags(char* flags, struct flag_list* fl, struct fs_mgr_flag_values* flag_vals,
+                            char* fs_options, int fs_options_len) {
+    uint64_t f = 0;
     int i;
     char *p;
     char *savep;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 072da97..7d1159b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -120,6 +120,8 @@
 #define MF_CHECKPOINT_FS  0x40000000
 #define MF_FIRST_STAGE_MOUNT \
                           0x80000000
+#define MF_SLOTSELECT_OTHER  \
+                         0x100000000
 // clang-format on
 
 #define DM_BUF_SIZE 4096
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index efc29bd..3cb718c 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -21,6 +21,19 @@
 #include "fs_mgr.h"
 #include "fs_mgr_priv.h"
 
+// https://source.android.com/devices/tech/ota/ab/ab_implement#partitions
+// All partitions that are A/B-ed should be named as follows (slots are always
+// named a, b, etc.): boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
+static std::string other_suffix(const std::string& slot_suffix) {
+    if (slot_suffix == "_a") {
+        return "_b";
+    }
+    if (slot_suffix == "_b") {
+        return "_a";
+    }
+    return "";
+}
+
 // Returns "_a" or "_b" based on androidboot.slot_suffix in kernel cmdline, or an empty string
 // if that parameter does not exist.
 std::string fs_mgr_get_slot_suffix() {
@@ -35,7 +48,7 @@
     std::string ab_suffix;
 
     for (auto& entry : *fstab) {
-        if (!entry.fs_mgr_flags.slot_select) {
+        if (!entry.fs_mgr_flags.slot_select && !entry.fs_mgr_flags.slot_select_other) {
             continue;
         }
 
@@ -45,8 +58,10 @@
             if (ab_suffix.empty()) return false;
         }
 
-        entry.blk_device = entry.blk_device + ab_suffix;
-        entry.logical_partition_name = entry.logical_partition_name + ab_suffix;
+        const auto& update_suffix =
+                entry.fs_mgr_flags.slot_select ? ab_suffix : other_suffix(ab_suffix);
+        entry.blk_device = entry.blk_device + update_suffix;
+        entry.logical_partition_name = entry.logical_partition_name + update_suffix;
     }
     return true;
 }
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index d9a5e0a..0997254 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -43,7 +43,7 @@
     char* fs_type;
     unsigned long flags;
     char* fs_options;
-    int fs_mgr_flags;
+    uint64_t fs_mgr_flags;
     char* key_loc;
     char* key_dir;
     char* verity_loc;
@@ -123,8 +123,9 @@
     // TODO: Remove this union once fstab_rec is deprecated. It only serves as a
     // convenient way to convert between fstab_rec::fs_mgr_flags and these bools.
     union {
-        int val;
+        uint64_t val;
         struct {
+            // bit 0
             bool wait : 1;
             bool check : 1;
             bool crypt : 1;
@@ -133,6 +134,8 @@
             bool length : 1;
             bool recovery_only : 1;
             bool swap_prio : 1;
+
+            // bit 8
             bool zram_size : 1;
             bool verify : 1;
             bool force_crypt : 1;
@@ -142,6 +145,8 @@
             bool file_encryption : 1;
             bool formattable : 1;
             bool slot_select : 1;
+
+            // bit 16
             bool force_fde_or_fbe : 1;
             bool late_mount : 1;
             bool no_fail : 1;
@@ -150,6 +155,8 @@
             bool reserved_size : 1;
             bool quota : 1;
             bool erase_blk_size : 1;
+
+            // bit 24
             bool logical_blk_size : 1;
             bool avb : 1;
             bool key_directory : 1;
@@ -158,6 +165,9 @@
             bool checkpoint_blk : 1;
             bool checkpoint_fs : 1;
             bool first_stage_mount : 1;
+
+            // bit 32
+            bool slot_select_other : 1;
         };
     } fs_mgr_flags;
 
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index aaee1a7..5957e30 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -290,6 +290,11 @@
 fi
 inAdb || die "specified device not in adb mode"
 isDebuggable || die "device not a debug build"
+enforcing=true
+if ! adb_su getenforce </dev/null | grep 'Enforcing' >/dev/null; then
+  echo "${ORANGE}[  WARNING ]${NORMAL} device does not have sepolicy in enforcing mode"
+  enforcing=false
+fi
 
 # Do something
 
@@ -535,9 +540,11 @@
   die "re-read system hello after reboot"
 check_eq "${A}" "${B}" system after reboot
 # Only root can read vendor if sepolicy permissions are as expected
-B="`adb_cat /vendor/hello`" &&
-  die "re-read vendor hello after reboot w/o root"
-check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
+if ${enforcing}; then
+  B="`adb_cat /vendor/hello`" &&
+    die "re-read vendor hello after reboot w/o root"
+  check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
+fi
 adb_root &&
   B="`adb_cat /vendor/hello`" ||
   die "re-read vendor hello after reboot"
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index c96c381..acefdf0 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -42,6 +42,7 @@
 #include "uevent_listener.h"
 #include "util.h"
 
+using android::base::ReadFileToString;
 using android::base::Split;
 using android::base::Timer;
 using android::fs_mgr::AvbHandle;
@@ -73,6 +74,8 @@
     bool CreateLogicalPartitions();
     bool MountPartition(FstabEntry* fstab_entry);
     bool MountPartitions();
+    bool TrySwitchSystemAsRoot();
+    bool TrySkipMountingPartitions();
     bool IsDmLinearEnabled();
     bool GetDmLinearMetadataDevice();
     bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
@@ -398,10 +401,10 @@
     return true;
 }
 
-bool FirstStageMount::MountPartitions() {
-    // If system is in the fstab then we're not a system-as-root device, and in
-    // this case, we mount system first then pivot to it.  From that point on,
-    // we are effectively identical to a system-as-root device.
+// If system is in the fstab then we're not a system-as-root device, and in
+// this case, we mount system first then pivot to it.  From that point on,
+// we are effectively identical to a system-as-root device.
+bool FirstStageMount::TrySwitchSystemAsRoot() {
     auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
         return entry.mount_point == "/system";
     });
@@ -416,6 +419,44 @@
         fstab_.erase(system_partition);
     }
 
+    return true;
+}
+
+// For GSI to skip mounting /product and /product_services, until there are
+// well-defined interfaces between them and /system. Otherwise, the GSI flashed
+// on /system might not be able to work with /product and /product_services.
+// When they're skipped here, /system/product and /system/product_services in
+// GSI will be used.
+bool FirstStageMount::TrySkipMountingPartitions() {
+    constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg";
+
+    std::string skip_config;
+    if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
+        return true;
+    }
+
+    for (const auto& skip_mount_point : Split(skip_config, "\n")) {
+        if (skip_mount_point.empty()) {
+            continue;
+        }
+        auto removing_entry =
+                std::find_if(fstab_.begin(), fstab_.end(), [&skip_mount_point](const auto& entry) {
+                    return entry.mount_point == skip_mount_point;
+                });
+        if (removing_entry != fstab_.end()) {
+            fstab_.erase(removing_entry);
+            LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
+        }
+    }
+
+    return true;
+}
+
+bool FirstStageMount::MountPartitions() {
+    if (!TrySwitchSystemAsRoot()) return false;
+
+    if (!TrySkipMountingPartitions()) return false;
+
     for (auto& fstab_entry : fstab_) {
         if (!MountPartition(&fstab_entry) && !fstab_entry.fs_mgr_flags.no_fail) {
             return false;
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index 969f26b..267da4a 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -510,9 +510,7 @@
     return android::base::Trim(content) == string;
 }
 
-void llkPanicKernel(bool dump, pid_t tid, const char* state,
-                    const std::string& message = "") __noreturn;
-void llkPanicKernel(bool dump, pid_t tid, const char* state, const std::string& message) {
+void llkPanicKernel(bool dump, pid_t tid, const char* state, const std::string& message = "") {
     if (!message.empty()) LOG(ERROR) << message;
     auto sysrqTriggerFd = llkFileToWriteFd("/proc/sysrq-trigger");
     if (sysrqTriggerFd < 0) {
@@ -521,6 +519,7 @@
         // The answer to life, the universe and everything
         ::exit(42);
         // NOTREACHED
+        return;
     }
     ::sync();
     if (dump) {
@@ -544,6 +543,13 @@
     llkWriteStringToFile(message + (message.empty() ? "" : "\n") +
                                  "SysRq : Trigger a crash : 'livelock,"s + state + "'\n",
                          "/dev/kmsg");
+    // Because panic is such a serious thing to do, let us
+    // make sure that the tid being inspected still exists!
+    auto piddir = procdir + std::to_string(tid) + "/stat";
+    if (access(piddir.c_str(), F_OK) != 0) {
+        PLOG(WARNING) << piddir;
+        return;
+    }
     android::base::WriteStringToFd("c", sysrqTriggerFd);
     // NOTREACHED
     // DYB
@@ -909,6 +915,7 @@
     ms -= llkCycle;
     auto myPid = ::getpid();
     auto myTid = ::gettid();
+    auto dump = true;
     for (auto dp = llkTopDirectory.read(); dp != nullptr; dp = llkTopDirectory.read()) {
         std::string piddir;
 
@@ -1109,9 +1116,10 @@
             const auto message = state + " "s + llkFormat(procp->count) + " " +
                                  std::to_string(ppid) + "->" + std::to_string(pid) + "->" +
                                  std::to_string(tid) + " " + procp->getComm() + " [panic]";
-            llkPanicKernel(true, tid,
+            llkPanicKernel(dump, tid,
                            (state == 'Z') ? "zombie" : (state == 'D') ? "driver" : "sleeping",
                            message);
+            dump = false;
         }
         LOG(VERBOSE) << "+closedir()";
     }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 349168e..6fb1a8b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -583,8 +583,8 @@
     # Set SELinux security contexts on upgrade or policy update.
     restorecon --recursive --skip-ce /data
 
-    # Check any timezone data in /data is newer than the copy in /system, delete if not.
-    exec - system system -- /system/bin/tzdatacheck /system/usr/share/zoneinfo /data/misc/zoneinfo
+    # Check any timezone data in /data is newer than the copy in the runtime module, delete if not.
+    exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo
 
     # If there is no post-fs-data action in the init.<device>.rc file, you
     # must uncomment this line, otherwise encrypted filesystems