Accept apex packages as argument.

Bug: 112669193
Test: Successfully reaches PackageManager. Doesn't break existing flows.
Change-Id: If4a173e290ebf0b70beb97111a6d75400da7ec8d
diff --git a/adb/adb.h b/adb/adb.h
index e2911e8..8c37c4b 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -59,7 +59,7 @@
 std::string adb_version();
 
 // Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 40
+#define ADB_SERVER_VERSION 41
 
 using TransportId = uint64_t;
 class atransport;
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 022666f..cf22efa 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -38,14 +38,22 @@
 
 static constexpr int kFastDeployMinApi = 24;
 
-static bool _use_legacy_install() {
+static bool can_use_feature(const char* feature) {
     FeatureSet features;
     std::string error;
     if (!adb_get_feature_set(&features, &error)) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return true;
     }
-    return !CanUseFeature(features, kFeatureCmd);
+    return CanUseFeature(features, feature);
+}
+
+static bool use_legacy_install() {
+    return !can_use_feature(kFeatureCmd);
+}
+
+static bool is_apex_supported() {
+    return can_use_feature(kFeatureApex);
 }
 
 static int pm_command(int argc, const char** argv) {
@@ -102,7 +110,7 @@
 }
 
 int uninstall_app(int argc, const char** argv) {
-    if (_use_legacy_install()) {
+    if (use_legacy_install()) {
         return uninstall_app_legacy(argc, argv);
     }
     return uninstall_app_streamed(argc, argv);
@@ -133,8 +141,21 @@
 
     // The last argument must be the APK file
     const char* file = argv[argc - 1];
-    if (!android::base::EndsWithIgnoreCase(file, ".apk")) {
-        error_exit("filename doesn't end .apk: %s", file);
+    if (!android::base::EndsWithIgnoreCase(file, ".apk") &&
+        !android::base::EndsWithIgnoreCase(file, ".apex")) {
+        error_exit("filename doesn't end .apk or .apex: %s", file);
+    }
+
+    bool is_apex = false;
+    if (android::base::EndsWithIgnoreCase(file, ".apex")) {
+        is_apex = true;
+    }
+    if (is_apex && !is_apex_supported()) {
+        error_exit(".apex is not supported on the target device");
+    }
+
+    if (is_apex && use_fastdeploy) {
+        error_exit("--fastdeploy doesn't support .apex files");
     }
 
     if (use_fastdeploy == true) {
@@ -177,6 +198,10 @@
         // do last to override any user specified value
         cmd += " " + android::base::StringPrintf("-S %" PRIu64, static_cast<uint64_t>(sb.st_size));
 
+        if (is_apex) {
+            cmd += " --apex";
+        }
+
         int remoteFd = adb_connect(cmd, &error);
         if (remoteFd < 0) {
             fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
@@ -218,6 +243,9 @@
     // All other arguments passed through verbatim.
     int last_apk = -1;
     for (int i = argc - 1; i >= 0; i--) {
+        if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) {
+            error_exit("APEX packages are only compatible with Streamed Install");
+        }
         if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) {
             last_apk = i;
             break;
@@ -303,14 +331,14 @@
     }
 
     if (installMode == INSTALL_DEFAULT) {
-        if (_use_legacy_install()) {
+        if (use_legacy_install()) {
             installMode = INSTALL_PUSH;
         } else {
             installMode = INSTALL_STREAM;
         }
     }
 
-    if (installMode == INSTALL_STREAM && _use_legacy_install() == true) {
+    if (installMode == INSTALL_STREAM && use_legacy_install() == true) {
         error_exit("Attempting to use streaming install on unsupported device");
     }
 
@@ -359,6 +387,9 @@
     uint64_t total_size = 0;
     for (int i = argc - 1; i >= 0; i--) {
         const char* file = argv[i];
+        if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) {
+            error_exit("APEX packages are not compatible with install-multiple");
+        }
 
         if (android::base::EndsWithIgnoreCase(file, ".apk") ||
             android::base::EndsWithIgnoreCase(file, ".dm")) {
@@ -373,7 +404,7 @@
     if (first_apk == -1) error_exit("need APK file on command line");
 
     std::string install_cmd;
-    if (_use_legacy_install()) {
+    if (use_legacy_install()) {
         install_cmd = "exec:pm";
     } else {
         install_cmd = "exec:cmd package";
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 0fbeec6..b65d676 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -66,6 +66,7 @@
 const char* const kFeatureStat2 = "stat_v2";
 const char* const kFeatureLibusb = "libusb";
 const char* const kFeaturePushSync = "push_sync";
+const char* const kFeatureApex = "apex";
 
 namespace {
 
@@ -1008,6 +1009,9 @@
     // Local static allocation to avoid global non-POD variables.
     static const FeatureSet* features = new FeatureSet{
         kFeatureShell2, kFeatureCmd, kFeatureStat2,
+#if ADB_HOST
+                kFeatureApex
+#endif
         // Increment ADB_SERVER_VERSION whenever the feature list changes to
         // make sure that the adb client and server features stay in sync
         // (http://b/24370690).
diff --git a/adb/transport.h b/adb/transport.h
index 1350e63..ea97270 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -59,6 +59,8 @@
 extern const char* const kFeatureLibusb;
 // The server supports `push --sync`.
 extern const char* const kFeaturePushSync;
+// The server supports installing .apex packages.
+extern const char* const kFeatureApex;
 
 TransportId NextTransportId();