Incremental apps removal on data loader failures.

Test: adb install --incremental megacity.apk over USB2.0, remove usb connection
after installed.
Bug: b/15041101

Change-Id: Ib848640dbe49c76021f7cf544de4413599c2c763
diff --git a/core/java/android/content/pm/IDataLoaderStatusListener.aidl b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
index 5011faa..9819b5d 100644
--- a/core/java/android/content/pm/IDataLoaderStatusListener.aidl
+++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
@@ -31,9 +31,7 @@
     const int DATA_LOADER_IMAGE_READY = 4;
     const int DATA_LOADER_IMAGE_NOT_READY = 5;
 
-    const int DATA_LOADER_SLOW_CONNECTION = 6;
-    const int DATA_LOADER_NO_CONNECTION = 7;
-    const int DATA_LOADER_CONNECTION_OK = 8;
+    const int DATA_LOADER_UNRECOVERABLE = 6;
 
     /** Data loader status callback */
     void onStatusChanged(in int dataLoaderId, in int status);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 45a25a0..9edc886 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1487,6 +1487,18 @@
         return e;
     }
 
+    private void onDataLoaderUnrecoverable() {
+        final PackageManagerService packageManagerService = mPm;
+        final String packageName = mPackageName;
+        mHandler.post(() -> {
+            if (packageManagerService.deletePackageX(packageName,
+                    PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM,
+                    PackageManager.DELETE_ALL_USERS) != PackageManager.DELETE_SUCCEEDED) {
+                Slog.e(TAG, "Failed to uninstall package with failed dataloader: " + packageName);
+            }
+        });
+    }
+
     /**
      * If session should be sealed, then it's sealed to prevent further modification.
      * If the session can't be sealed then it's destroyed.
@@ -2564,11 +2576,20 @@
         IDataLoaderStatusListener listener = new IDataLoaderStatusListener.Stub() {
             @Override
             public void onStatusChanged(int dataLoaderId, int status) {
-                try {
-                    if (status == IDataLoaderStatusListener.DATA_LOADER_DESTROYED) {
+                switch (status) {
+                    case IDataLoaderStatusListener.DATA_LOADER_STOPPED:
+                    case IDataLoaderStatusListener.DATA_LOADER_DESTROYED:
                         return;
-                    }
+                    case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
+                        onDataLoaderUnrecoverable();
+                        return;
+                }
 
+                if (mDestroyed || mDataLoaderFinished) {
+                    return;
+                }
+
+                try {
                     IDataLoader dataLoader = dataLoaderManager.getDataLoader(dataLoaderId);
                     if (dataLoader == null) {
                         mDataLoaderFinished = true;
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 29b2cd6..5f0c8fe3 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -598,6 +598,9 @@
     // IFS callbacks.
     void onPendingReads(dataloader::PendingReads pendingReads) final {
         std::lock_guard lock{mOutFdLock};
+        if (mOutFd < 0) {
+            return;
+        }
         CHECK(mIfs);
         for (auto&& pendingRead : pendingReads) {
             const android::dataloader::FileId& fileId = pendingRead.id;
@@ -611,13 +614,9 @@
                       android::incfs::toString(fileId).c_str());
                 continue;
             }
-            if (mRequestedFiles.insert(fileIdx).second) {
-                if (!sendRequest(mOutFd, PREFETCH, fileIdx, blockIdx)) {
-                    ALOGE("Failed to request prefetch for fileid=%s. Ignore.",
-                          android::incfs::toString(fileId).c_str());
-                    mRequestedFiles.erase(fileIdx);
-                    mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
-                }
+            if (mRequestedFiles.insert(fileIdx).second &&
+                !sendRequest(mOutFd, PREFETCH, fileIdx, blockIdx)) {
+                mRequestedFiles.erase(fileIdx);
             }
             sendRequest(mOutFd, BLOCK_MISSING, fileIdx, blockIdx);
         }
@@ -634,7 +633,7 @@
             }
             if (res < 0) {
                 ALOGE("Failed to poll. Abort.");
-                mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
+                mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
                 break;
             }
             if (res == mEventFd) {
@@ -644,7 +643,7 @@
             }
             if (!readChunk(inout, data)) {
                 ALOGE("Failed to read a message. Abort.");
-                mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
+                mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
                 break;
             }
             auto remainingData = std::span(data);
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 4da0091..e24b76c 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1248,14 +1248,6 @@
     }
 
     switch (newStatus) {
-        case IDataLoaderStatusListener::DATA_LOADER_NO_CONNECTION: {
-            // TODO(b/150411019): handle data loader connection loss
-            break;
-        }
-        case IDataLoaderStatusListener::DATA_LOADER_CONNECTION_OK: {
-            // TODO(b/150411019): handle data loader connection loss
-            break;
-        }
         case IDataLoaderStatusListener::DATA_LOADER_CREATED: {
             if (startRequested) {
                 incrementalService.startDataLoader(mountId);
@@ -1277,6 +1269,10 @@
         case IDataLoaderStatusListener::DATA_LOADER_IMAGE_NOT_READY: {
             break;
         }
+        case IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE: {
+            // Nothing for now. Rely on externalListener to handle this.
+            break;
+        }
         default: {
             LOG(WARNING) << "Unknown data loader status: " << newStatus
                          << " for mount: " << mountId;