Skip the f2fs check for the automotive devices in Android 13. am: a3e0d50468 am: 1863abd733 am: cacc6a75bf am: ccd1383721 am: f71ecd3aeb am: f05e390bf9 am: fc104df9bf

Original change: https://android-review.googlesource.com/c/platform/system/gsid/+/2557090

Change-Id: I9f63ac8974a0bd5c5d5cda72ad4f49912419a3cc
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index 50618f9..1b78971 100644
--- a/Android.bp
+++ b/Android.bp
@@ -74,21 +74,19 @@
     recovery_available: true,
     vendor_available: true,
     export_include_dirs: ["include"],
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
+    min_sdk_version: "31",
 }
 
-cc_binary {
-    name: "gsid",
+cc_defaults {
+    name: "gsid_defaults",
     srcs: [
-        "daemon.cpp",
         "gsi_service.cpp",
         "partition_installer.cpp",
     ],
-    required: [
-        "mke2fs",
-    ],
-    init_rc: [
-        "gsid.rc",
-    ],
     shared_libs: [
         "libbase",
         "libbinder",
@@ -124,6 +122,22 @@
     local_include_dirs: ["include"],
 }
 
+cc_binary {
+    name: "gsid",
+    defaults: [
+        "gsid_defaults",
+    ],
+    srcs: [
+        "daemon.cpp",
+    ],
+    required: [
+        "mke2fs",
+    ],
+    init_rc: [
+        "gsid.rc",
+    ],
+}
+
 aidl_interface {
     name: "gsi_aidl_interface",
     unstable: true,
@@ -149,3 +163,22 @@
     ],
     path: "aidl",
 }
+
+cc_fuzz {
+    name: "gsi_service_fuzzer",
+    defaults: [
+        "gsid_defaults",
+        "service_fuzzer_defaults",
+        "fuzzer_disable_leaks",
+    ],
+    srcs: [
+        "fuzzers/GsiServiceFuzzer.cpp",
+    ],
+    fuzz_config: {
+        triage_assignee: "waghpawan@google.com",
+        cc: [
+            "elsk@google.com",
+            "yochiang@google.com",
+        ]
+    },
+}
diff --git a/OWNERS b/OWNERS
index a9d0479..e8bcfb2 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,4 @@
-# Bug component: 30545
+# Bug component: 322150
 dvander@google.com
 sspatil@google.com
 elsk@google.com
diff --git a/fuzzers/GsiServiceFuzzer.cpp b/fuzzers/GsiServiceFuzzer.cpp
new file mode 100644
index 0000000..1d100d8
--- /dev/null
+++ b/fuzzers/GsiServiceFuzzer.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzbinder/libbinder_driver.h>
+
+#include "gsi_service.h"
+
+using android::fuzzService;
+using android::sp;
+using android::gsi::GsiService;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    auto binder = sp<GsiService>::make();
+    fuzzService(binder, FuzzedDataProvider(data, size));
+    return 0;
+}
\ No newline at end of file
diff --git a/gsi_service.cpp b/gsi_service.cpp
index 6fc593e..224f520 100644
--- a/gsi_service.cpp
+++ b/gsi_service.cpp
@@ -352,10 +352,11 @@
 }
 
 binder::Status GsiService::removeGsiAsync(const sp<IGsiServiceCallback>& resultCallback) {
-    bool result = false;
-    auto status = removeGsi(&result);
-    if (!status.isOk()) {
-        LOG(ERROR) << "Could not removeGsi: " << status.exceptionMessage().string();
+    int result = IGsiService::INSTALL_OK;
+    bool success = true;
+    auto status = removeGsi(&success);
+    if (!status.isOk() || !success) {
+        LOG(ERROR) << "Could not removeGsi: " << status.exceptionMessage().c_str();
         result = IGsiService::INSTALL_ERROR_GENERIC;
     }
     resultCallback->onResult(result);
@@ -505,6 +506,12 @@
         return binder::Status::ok();
     }
     int fd = installer_->GetPartitionFd();
+    if (fd == -1) {
+        LOG(ERROR) << "Failed to get partition fd";
+        *_aidl_return = INSTALL_ERROR_GENERIC;
+        return binder::Status::ok();
+    }
+
     if (!GetAvbPublicKeyFromFd(fd, dst)) {
         LOG(ERROR) << "Failed to extract AVB public key";
         *_aidl_return = INSTALL_ERROR_GENERIC;
@@ -619,7 +626,7 @@
             auto status = on_progress->onProgress(static_cast<int64_t>(current),
                                                   static_cast<int64_t>(total));
             if (!status.isOk()) {
-                LOG(ERROR) << "progress callback returned: " << status.toString8().string();
+                LOG(ERROR) << "progress callback returned: " << status.toString8().c_str();
                 return false;
             }
             return true;
diff --git a/gsi_service.h b/gsi_service.h
index 3c4c278..0dce269 100644
--- a/gsi_service.h
+++ b/gsi_service.h
@@ -86,11 +86,11 @@
     std::string GetActiveInstalledImageDir();
 
     static std::vector<std::string> GetInstalledDsuSlots();
+    GsiService();
 
   private:
     friend class ImageService;
 
-    GsiService();
     static int ValidateInstallParams(std::string& install_dir);
     int EnableGsi(bool one_shot, const std::string& dsu_slot);
     bool DisableGsiInstall();
diff --git a/gsi_tool.cpp b/gsi_tool.cpp
index 01033ae..6aa0fb5 100644
--- a/gsi_tool.cpp
+++ b/gsi_tool.cpp
@@ -83,7 +83,7 @@
 static std::string ErrorMessage(const android::binder::Status& status,
                                 int error_code = IGsiService::INSTALL_ERROR_GENERIC) {
     if (!status.isOk()) {
-        return status.exceptionMessage().string();
+        return status.exceptionMessage().c_str();
     }
     return "error code " + std::to_string(error_code);
 }
@@ -533,7 +533,7 @@
     bool running;
     auto status = gsid->isGsiRunning(&running);
     if (!status.isOk()) {
-        std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
+        std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
         return EX_SOFTWARE;
     }
     if (running) {
@@ -544,7 +544,7 @@
     bool installed;
     status = gsid->isGsiInstalled(&installed);
     if (!status.isOk()) {
-        std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
+        std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
         return EX_SOFTWARE;
     }
     if (!installed) {
@@ -569,7 +569,7 @@
     bool running;
     auto status = gsid->isGsiRunning(&running);
     if (!status.isOk()) {
-        std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
+        std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
         return EX_SOFTWARE;
     } else if (running) {
         std::cout << "running" << std::endl;
@@ -577,7 +577,7 @@
     bool installed;
     status = gsid->isGsiInstalled(&installed);
     if (!status.isOk()) {
-        std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
+        std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
         return EX_SOFTWARE;
     } else if (installed) {
         std::cout << "installed" << std::endl;
@@ -585,7 +585,7 @@
     bool enabled;
     status = gsid->isGsiEnabled(&enabled);
     if (!status.isOk()) {
-        std::cerr << status.exceptionMessage().string() << std::endl;
+        std::cerr << status.exceptionMessage().c_str() << std::endl;
         return EX_SOFTWARE;
     } else if (running || installed) {
         std::cout << (enabled ? "enabled" : "disabled") << std::endl;
@@ -599,7 +599,7 @@
     std::vector<std::string> dsu_slots;
     status = gsid->getInstalledDsuSlots(&dsu_slots);
     if (!status.isOk()) {
-        std::cerr << status.exceptionMessage().string() << std::endl;
+        std::cerr << status.exceptionMessage().c_str() << std::endl;
         return EX_SOFTWARE;
     }
     int n = 0;
@@ -613,13 +613,13 @@
                 // because we can't stat the "outside" userdata.
                 continue;
             }
-            std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
+            std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
             return EX_SOFTWARE;
         }
         std::vector<std::string> images;
         status = image_service->getAllBackingImages(&images);
         if (!status.isOk()) {
-            std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
+            std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
             return EX_SOFTWARE;
         }
         for (auto&& image : images) {
@@ -645,7 +645,7 @@
     bool cancelled = false;
     auto status = gsid->cancelGsiInstall(&cancelled);
     if (!status.isOk()) {
-        std::cerr << status.exceptionMessage().string() << std::endl;
+        std::cerr << status.exceptionMessage().c_str() << std::endl;
         return EX_SOFTWARE;
     }
     if (!cancelled) {
diff --git a/libgsid.cpp b/libgsid.cpp
index 4689dcd..fc75c90 100644
--- a/libgsid.cpp
+++ b/libgsid.cpp
@@ -27,7 +27,7 @@
 sp<IGsiService> GetGsiService() {
     auto sm = android::defaultServiceManager();
     auto name = android::String16(kGsiServiceName);
-    android::sp<android::IBinder> res = sm->waitForService(name);
+    static android::sp<android::IBinder> res = sm->waitForService(name);
     if (res) {
         return android::interface_cast<IGsiService>(res);
     }
diff --git a/partition_installer.cpp b/partition_installer.cpp
index ebd3b64..ebfb329 100644
--- a/partition_installer.cpp
+++ b/partition_installer.cpp
@@ -256,6 +256,9 @@
 }
 
 int PartitionInstaller::GetPartitionFd() {
+    if (!system_device_) {
+        return -1;
+    }
     return system_device_->fd();
 }
 
diff --git a/tests/DSUEndtoEndTest.java b/tests/DSUEndtoEndTest.java
index 79799bf..8179d59 100644
--- a/tests/DSUEndtoEndTest.java
+++ b/tests/DSUEndtoEndTest.java
@@ -21,16 +21,20 @@
 import com.android.tradefed.config.Option;
 import com.android.tradefed.config.Option.Importance;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.SparseImageUtil;
+import com.android.tradefed.util.StreamUtil;
 import com.android.tradefed.util.ZipUtil2;
 
 import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.junit.Before;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -40,7 +44,6 @@
 public class DSUEndtoEndTest extends DsuTestBase {
     private static final long kDefaultUserdataSize = 4L * 1024 * 1024 * 1024;
     private static final String LPUNPACK_PATH = "bin/lpunpack";
-    private static final String SIMG2IMG_PATH = "bin/simg2img";
 
     // Example: atest -v DSUEndtoEndTest -- --test-arg \
     // com.android.tradefed.testtype.HostTest:set-option:system_image_path:/full/path/to/system.img
@@ -51,56 +54,83 @@
             importance=Importance.ALWAYS)
     private String mSystemImagePath;
 
-    private File mUnsparseSystemImage;
+    private File mTempDir;
+
+    private File getTempPath(String relativePath) throws IOException {
+        if (mTempDir == null) {
+            mTempDir = FileUtil.createTempDir("DSUEndtoEndTest");
+        }
+        return new File(mTempDir, relativePath);
+    }
+
+    /** Extract system.img from build info to a temproary file. */
+    private File extractSystemImageFromBuildInfo(IBuildInfo buildInfo)
+            throws IOException, InterruptedException {
+        File imgZip = ((IDeviceBuildInfo) buildInfo).getDeviceImageFile();
+        Assert.assertNotNull(
+                "Failed to fetch system image. See system_image_path parameter", imgZip);
+
+        File superImg = getTempPath("super.img");
+        try (ZipFile zip = new ZipFile(imgZip)) {
+            File systemImg = getTempPath("system.img");
+            if (ZipUtil2.extractFileFromZip(zip, "system.img", systemImg)) {
+                return systemImg;
+            }
+            Assert.assertTrue(
+                    "No system.img or super.img in img zip.",
+                    ZipUtil2.extractFileFromZip(zip, "super.img", superImg));
+        }
+
+        if (SparseImageUtil.isSparse(superImg)) {
+            File unsparseSuperImage = getTempPath("super.raw");
+            SparseImageUtil.unsparse(superImg, unsparseSuperImage);
+            superImg = unsparseSuperImage;
+        }
+
+        File otaTools = buildInfo.getFile("otatools.zip");
+        Assert.assertNotNull("No otatools.zip in BuildInfo.", otaTools);
+        File otaToolsDir = getTempPath("otatools");
+        ZipUtil2.extractZip(otaTools, otaToolsDir);
+
+        String lpunpackPath = new File(otaToolsDir, LPUNPACK_PATH).getAbsolutePath();
+        File outputDir = getTempPath("lpunpack_output");
+        outputDir.mkdirs();
+        String[] cmd = {
+            lpunpackPath, "-p", "system_a", superImg.getAbsolutePath(), outputDir.getAbsolutePath()
+        };
+        Process p = Runtime.getRuntime().exec(cmd);
+        p.waitFor();
+        if (p.exitValue() != 0) {
+            String stderr = StreamUtil.getStringFromStream(p.getErrorStream());
+            Assert.fail(String.format("lpunpack returned %d. (%s)", p.exitValue(), stderr));
+        }
+        return new File(outputDir, "system_a.img");
+    }
+
+    @Before
+    public void setUp() {
+        mTempDir = null;
+    }
 
     @After
-    public void teardown() throws Exception {
-        if (mUnsparseSystemImage != null) {
-            mUnsparseSystemImage.delete();
-        }
+    public void tearDown() {
+        FileUtil.recursiveDelete(mTempDir);
     }
 
     @Test
     public void testDSU() throws Exception {
-        String simg2imgPath = "simg2img";
-        if (mSystemImagePath == null) {
-            IBuildInfo buildInfo = getBuild();
-            File imgs = ((IDeviceBuildInfo) buildInfo).getDeviceImageFile();
-            Assert.assertNotEquals("Failed to fetch system image. See system_image_path parameter", null, imgs);
-            File otaTools = buildInfo.getFile("otatools.zip");
-            File tempdir = ZipUtil2.extractZipToTemp(otaTools, "otatools");
-            File system = ZipUtil2.extractFileFromZip(new ZipFile(imgs), "system.img");
-            if (system == null) {
-                File superImg = ZipUtil2.extractFileFromZip(new ZipFile(imgs), "super.img");
-                String lpunpackPath = new File(tempdir, LPUNPACK_PATH).getAbsolutePath();
-                String outputDir = superImg.getParentFile().getAbsolutePath();
-                String[] cmd = {lpunpackPath, "-p", "system_a", superImg.getAbsolutePath(), outputDir};
-                Process p = Runtime.getRuntime().exec(cmd);
-                p.waitFor();
-                if (p.exitValue() == 0) {
-                    mSystemImagePath = new File(outputDir, "system_a.img").getAbsolutePath();
-                } else {
-                    ByteArrayOutputStream stderr = new ByteArrayOutputStream();
-                    int len;
-                    byte[] buf = new byte[1024];
-                    while ((len = p.getErrorStream().read(buf)) != -1) {
-                          stderr.write(buf, 0, len);
-                    }
-                    Assert.assertEquals("non-zero exit value (" + stderr.toString("UTF-8") + ")", 0, p.exitValue());
-                }
-            } else {
-                mSystemImagePath = system.getAbsolutePath();
-            }
-            simg2imgPath = new File(tempdir, SIMG2IMG_PATH).getAbsolutePath();
+        File systemImage;
+        if (mSystemImagePath != null) {
+            systemImage = new File(mSystemImagePath);
+        } else {
+            systemImage = extractSystemImageFromBuildInfo(getBuild());
         }
-        File gsi = new File(mSystemImagePath);
-        Assert.assertTrue("not a valid file", gsi.isFile());
-        String[] cmd = {simg2imgPath, mSystemImagePath, mSystemImagePath + ".raw"};
-        Process p = Runtime.getRuntime().exec(cmd);
-        p.waitFor();
-        if (p.exitValue() == 0) {
-            mUnsparseSystemImage = new File(mSystemImagePath + ".raw");
-            gsi = mUnsparseSystemImage;
+        Assert.assertTrue("not a valid file", systemImage.isFile());
+
+        if (SparseImageUtil.isSparse(systemImage)) {
+            File unsparseSystemImage = getTempPath("system.raw");
+            SparseImageUtil.unsparse(systemImage, unsparseSystemImage);
+            systemImage = unsparseSystemImage;
         }
 
         boolean wasRoot = getDevice().isAdbRoot();
@@ -117,8 +147,8 @@
                                 "gsi_tool install --userdata-size %d"
                                         + " --gsi-size %d"
                                         + " && sleep 10000000",
-                                getDsuUserdataSize(kDefaultUserdataSize), gsi.length()),
-                        gsi,
+                                getDsuUserdataSize(kDefaultUserdataSize), systemImage.length()),
+                        systemImage,
                         null,
                         10,
                         TimeUnit.MINUTES,
diff --git a/tests/DsuGsiIntegrationTest.java b/tests/DsuGsiIntegrationTest.java
index 78d001c..bb0014a 100644
--- a/tests/DsuGsiIntegrationTest.java
+++ b/tests/DsuGsiIntegrationTest.java
@@ -122,6 +122,7 @@
                 getDevice().executeShellV2Command("gsi_tool wipe");
                 if (isDsuRunning()) {
                     getDevice().reboot();
+                    getDevice().disableAdbRoot();
                 }
             } catch (DeviceNotAvailableException e) {
                 CLog.w("Failed to clean up DSU installation on device: %s", e);
@@ -140,6 +141,7 @@
             CLog.i("Wipe existing DSU installation");
             assertShellCommand("gsi_tool wipe");
             getDevice().reboot();
+            getDevice().disableAdbRoot();
             assertDsuNotRunning();
         }
 
@@ -160,6 +162,7 @@
 
         CLog.i("Test 'gsi_tool enable -s' and 'gsi_tool enable'");
         getDevice().reboot();
+        getDevice().disableAdbRoot();
         assertDsuNotRunning();
 
         final long freeSpaceAfterInstall = getDevice().getPartitionFreeSpace("/data") << 10;
@@ -173,12 +176,14 @@
 
         assertShellCommand("gsi_tool enable");
         getDevice().reboot();
+        getDevice().disableAdbRoot();
         assertDsuRunning();
 
         CLog.i("Set up 'adb remount' for testing (requires reboot)");
         assertAdbRoot();
         assertShellCommand("remount");
         getDevice().reboot();
+        getDevice().disableAdbRoot();
         assertDsuRunning();
         assertAdbRoot();
         assertShellCommand("remount");
@@ -190,12 +195,14 @@
         CLog.i("DSU and original system have separate remount overlays");
         assertShellCommand("gsi_tool disable");
         getDevice().reboot();
+        getDevice().disableAdbRoot();
         assertDsuNotRunning();
         assertDevicePathNotExist(REMOUNT_TEST_PATH);
 
         CLog.i("Test that 'adb remount' is consistent after reboot");
         assertShellCommand("gsi_tool enable");
         getDevice().reboot();
+        getDevice().disableAdbRoot();
         assertDsuRunning();
         assertDevicePathExist(REMOUNT_TEST_FILE);
         assertEquals(
@@ -208,12 +215,14 @@
         assertAdbRoot();
         assertShellCommand("enable-verity");
         getDevice().reboot();
+        getDevice().disableAdbRoot();
         assertDsuRunning();
         assertDevicePathNotExist(REMOUNT_TEST_PATH);
 
         CLog.i("Test 'gsi_tool wipe'");
         assertShellCommand("gsi_tool wipe");
         getDevice().reboot();
+        getDevice().disableAdbRoot();
         assertDsuNotRunning();
 
         final double dampeningCoefficient = 0.9;