Migrating Incremental* APIs to PackageManager APIs.

Step 2, merging Data Loader params.

Test: builds and flashes
Bug: b/136132412

Change-Id: I2102554316dadcdcb49790c133ece110c43c29b3
diff --git a/core/java/android/content/pm/DataLoaderParams.java b/core/java/android/content/pm/DataLoaderParams.java
index af4b99a..60d7bb3 100644
--- a/core/java/android/content/pm/DataLoaderParams.java
+++ b/core/java/android/content/pm/DataLoaderParams.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.content.ComponentName;
 import android.os.ParcelFileDescriptor;
 
 import java.util.Arrays;
@@ -26,7 +27,7 @@
 import java.util.stream.Collectors;
 
 /**
- * This class represents the parameters used to configure an Incremental Data Loader.
+ * This class represents the parameters used to configure a Data Loader.
  *
  * WARNING: This is a system API to aid internal development.
  * Use at your own risk. It will change or be removed without warning.
@@ -34,13 +35,41 @@
  */
 @SystemApi
 public class DataLoaderParams {
-    @NonNull private final DataLoaderParamsParcel mData;
+    @NonNull
+    private final DataLoaderParamsParcel mData;
 
-    public DataLoaderParams(@NonNull String url, @NonNull String packageName,
+    /**
+     * Creates and populates set of Data Loader parameters for Streaming installation.
+     *
+     * @param componentName Data Loader component supporting Streaming installation.
+     * @param arguments free form installation arguments
+     */
+    public static final @NonNull DataLoaderParams forStreaming(@NonNull ComponentName componentName,
+            @NonNull String arguments) {
+        return new DataLoaderParams(DataLoaderType.STREAMING, componentName, arguments, null);
+    }
+
+    /**
+     * Creates and populates set of Data Loader parameters for Incremental installation.
+     *
+     * @param componentName Data Loader component supporting Incremental installation.
+     * @param arguments free form installation arguments
+     * @param namedFds TODO(b/146080380) remove
+     */
+    public static final @NonNull DataLoaderParams forIncremental(
+            @NonNull ComponentName componentName, @NonNull String arguments,
             @Nullable Map<String, ParcelFileDescriptor> namedFds) {
+        return new DataLoaderParams(DataLoaderType.INCREMENTAL, componentName, arguments, namedFds);
+    }
+
+    /** @hide */
+    public DataLoaderParams(@NonNull @DataLoaderType int type, @NonNull ComponentName componentName,
+            @NonNull String arguments, @Nullable Map<String, ParcelFileDescriptor> namedFds) {
         DataLoaderParamsParcel data = new DataLoaderParamsParcel();
-        data.staticArgs = url;
-        data.packageName = packageName;
+        data.type = type;
+        data.packageName = componentName.getPackageName();
+        data.className = componentName.getClassName();
+        data.arguments = arguments;
         if (namedFds == null || namedFds.isEmpty()) {
             data.dynamicArgs = new NamedParcelFileDescriptor[0];
         } else {
@@ -56,39 +85,42 @@
         mData = data;
     }
 
-    /**
-     * @hide
-     */
-    public DataLoaderParams(@NonNull DataLoaderParamsParcel data) {
+    /** @hide */
+    DataLoaderParams(@NonNull DataLoaderParamsParcel data) {
         mData = data;
     }
 
-    /**
-     * @return static server's URL
-     */
-    public final @NonNull String getStaticArgs() {
-        return mData.staticArgs;
-    }
-
-    /**
-     * @return data loader's package name
-     */
-    public final @NonNull String getPackageName() {
-        return mData.packageName;
-    }
-
-    /**
-     * @hide
-     */
+    /** @hide */
     public final @NonNull DataLoaderParamsParcel getData() {
         return mData;
     }
 
     /**
-     * @return data loader's dynamic arguments such as file descriptors
+     * @return data loader type
+     */
+    public final @NonNull @DataLoaderType int getType() {
+        return mData.type;
+    }
+
+    /**
+     * @return data loader's component name
+     */
+    public final @NonNull ComponentName getComponentName() {
+        return new ComponentName(mData.packageName, mData.className);
+    }
+
+    /**
+     * @return data loader's arguments
+     */
+    public final @NonNull String getArguments() {
+        return mData.arguments;
+    }
+
+    /**
+     * @return data loader's dynamic arguments such as file descriptors TODO: remove
      */
     public final @NonNull Map<String, ParcelFileDescriptor> getDynamicArgs() {
         return Arrays.stream(mData.dynamicArgs).collect(
-            Collectors.toMap(p->p.name, p->p.fd));
+                Collectors.toMap(p -> p.name, p -> p.fd));
     }
 }
diff --git a/core/java/android/content/pm/DataLoaderParamsParcel.aidl b/core/java/android/content/pm/DataLoaderParamsParcel.aidl
index 3316398..e05843b 100644
--- a/core/java/android/content/pm/DataLoaderParamsParcel.aidl
+++ b/core/java/android/content/pm/DataLoaderParamsParcel.aidl
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.content.pm.DataLoaderType;
 import android.content.pm.NamedParcelFileDescriptor;
 
 /**
@@ -23,7 +24,9 @@
  * @hide
  */
 parcelable DataLoaderParamsParcel {
+    DataLoaderType type;
     @utf8InCpp String packageName;
-    @utf8InCpp String staticArgs;
+    @utf8InCpp String className;
+    @utf8InCpp String arguments;
     NamedParcelFileDescriptor[] dynamicArgs;
 }
diff --git a/core/java/android/content/pm/DataLoaderType.aidl b/core/java/android/content/pm/DataLoaderType.aidl
new file mode 100644
index 0000000..7d726f5
--- /dev/null
+++ b/core/java/android/content/pm/DataLoaderType.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.content.pm;
+
+/**
+ * Types of Data Loader for an installation session.
+ * @hide
+ */
+@Backing(type="int")
+enum DataLoaderType {
+    /**
+    * Default value, legacy installation.
+    */
+    NONE = 0,
+    /**
+     * Streaming installation using data loader.
+     */
+    STREAMING = 1,
+    /**
+     * Streaming installation using Incremental FileSystem.
+     */
+    INCREMENTAL = 2,
+}
diff --git a/core/java/android/content/pm/IDataLoader.aidl b/core/java/android/content/pm/IDataLoader.aidl
index c65bd6a..b5baa93 100644
--- a/core/java/android/content/pm/IDataLoader.aidl
+++ b/core/java/android/content/pm/IDataLoader.aidl
@@ -27,7 +27,9 @@
  */
 oneway interface IDataLoader {
    void create(int id, in Bundle params, IDataLoaderStatusListener listener);
-   void start(in List<InstallationFile> fileInfos);
+   void start();
    void stop();
    void destroy();
+
+   void prepareImage(in List<InstallationFile> addedFiles, in List<String> removedFiles);
 }
diff --git a/core/java/android/content/pm/IDataLoaderStatusListener.aidl b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
index a60d6ee..5011faa 100644
--- a/core/java/android/content/pm/IDataLoaderStatusListener.aidl
+++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
@@ -22,13 +22,18 @@
  */
 oneway interface IDataLoaderStatusListener {
     /** Data loader status */
-    const int DATA_LOADER_READY = 0;
-    const int DATA_LOADER_NOT_READY = 1;
-    const int DATA_LOADER_RUNNING = 2;
+    const int DATA_LOADER_CREATED = 0;
+    const int DATA_LOADER_DESTROYED = 1;
+
+    const int DATA_LOADER_STARTED = 2;
     const int DATA_LOADER_STOPPED = 3;
-    const int DATA_LOADER_SLOW_CONNECTION = 4;
-    const int DATA_LOADER_NO_CONNECTION = 5;
-    const int DATA_LOADER_CONNECTION_OK = 6;
+
+    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;
 
     /** Data loader status callback */
     void onStatusChanged(in int dataLoaderId, in int status);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3d6d849..e4a0bc0 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1461,10 +1461,7 @@
         /** {@hide} */
         public long requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
         /** {@hide} */
-        public DataLoaderParams incrementalParams;
-        /** TODO(b/146080380): add a class name to make it fully compatible with ComponentName.
-         * {@hide} */
-        public String dataLoaderPackageName;
+        public DataLoaderParams dataLoaderParams;
         /** {@hide} */
         public int rollbackDataPolicy = PackageManager.RollbackDataPolicy.RESTORE;
 
@@ -1503,10 +1500,8 @@
             DataLoaderParamsParcel dataLoaderParamsParcel = source.readParcelable(
                     DataLoaderParamsParcel.class.getClassLoader());
             if (dataLoaderParamsParcel != null) {
-                incrementalParams = new DataLoaderParams(
-                        dataLoaderParamsParcel);
+                dataLoaderParams = new DataLoaderParams(dataLoaderParamsParcel);
             }
-            dataLoaderPackageName = source.readString();
             rollbackDataPolicy = source.readInt();
         }
 
@@ -1531,8 +1526,7 @@
             ret.isMultiPackage = isMultiPackage;
             ret.isStaged = isStaged;
             ret.requiredInstalledVersionCode = requiredInstalledVersionCode;
-            ret.incrementalParams = incrementalParams;
-            ret.dataLoaderPackageName = dataLoaderPackageName;
+            ret.dataLoaderParams = dataLoaderParams;
             ret.rollbackDataPolicy = rollbackDataPolicy;
             return ret;
         }
@@ -1893,29 +1887,18 @@
         }
 
         /**
-         * Set Incremental data loader params.
+         * Set the data loader params for the session.
+         * This also switches installation into data provider mode and disallow direct writes into
+         * staging folder.
+         *
          * WARNING: This is a system API to aid internal development.
          * Use at your own risk. It will change or be removed without warning.
          * {@hide}
          */
         @SystemApi
         @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
-        public void setIncrementalParams(@NonNull DataLoaderParams incrementalParams) {
-            this.incrementalParams = incrementalParams;
-        }
-
-        /**
-         * Set the data provider params for the session.
-         * This also switches installation into callback mode and disallow direct writes into
-         * staging folder.
-         * TODO(b/146080380): unify dataprovider params with Incremental.
-         *
-         * @param dataLoaderPackageName name of the dataLoader package
-         * {@hide}
-         */
-        @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
-        public void setDataLoaderPackageName(String dataLoaderPackageName) {
-            this.dataLoaderPackageName = dataLoaderPackageName;
+        public void setDataLoaderParams(@NonNull DataLoaderParams dataLoaderParams) {
+            this.dataLoaderParams = dataLoaderParams;
         }
 
         /** {@hide} */
@@ -1938,7 +1921,7 @@
             pw.printPair("isMultiPackage", isMultiPackage);
             pw.printPair("isStaged", isStaged);
             pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode);
-            pw.printPair("dataLoaderPackageName", dataLoaderPackageName);
+            pw.printPair("dataLoaderParams", dataLoaderParams);
             pw.printPair("rollbackDataPolicy", rollbackDataPolicy);
             pw.println();
         }
@@ -1969,12 +1952,11 @@
             dest.writeBoolean(isMultiPackage);
             dest.writeBoolean(isStaged);
             dest.writeLong(requiredInstalledVersionCode);
-            if (incrementalParams != null) {
-                dest.writeParcelable(incrementalParams.getData(), flags);
+            if (dataLoaderParams != null) {
+                dest.writeParcelable(dataLoaderParams.getData(), flags);
             } else {
                 dest.writeParcelable(null, flags);
             }
-            dest.writeString(dataLoaderPackageName);
             dest.writeInt(rollbackDataPolicy);
         }
 
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index fb94fc9..2138d553 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -87,8 +87,8 @@
         mPackageName = packageName;
         mStageDir = stageDir;
         mIncrementalManager = incrementalManager;
-        if (dataLoaderParams.getPackageName().equals("local")) {
-            final String incrementalPath = dataLoaderParams.getStaticArgs();
+        if (dataLoaderParams.getComponentName().getPackageName().equals("local")) {
+            final String incrementalPath = dataLoaderParams.getArguments();
             mDefaultStorage = mIncrementalManager.openStorage(incrementalPath);
             mDefaultDir = incrementalPath;
             return;
diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java
index 54a4fa6..75f252e 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -16,7 +16,6 @@
 
 package android.service.dataloader;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -27,19 +26,16 @@
 import android.content.pm.FileSystemControlParcel;
 import android.content.pm.IDataLoader;
 import android.content.pm.IDataLoaderStatusListener;
-import android.content.pm.IPackageInstallerSessionFileSystemConnector;
 import android.content.pm.InstallationFile;
 import android.content.pm.NamedParcelFileDescriptor;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
 import android.util.ExceptionUtils;
 import android.util.Slog;
 
 import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -55,88 +51,35 @@
  */
 @SystemApi
 public abstract class DataLoaderService extends Service {
-    private static final String TAG = "IncrementalDataLoaderService";
+    private static final String TAG = "DataLoaderService";
     private final DataLoaderBinderService mBinder = new DataLoaderBinderService();
 
-    /** @hide */
-    public static final int DATA_LOADER_READY =
-            IDataLoaderStatusListener.DATA_LOADER_READY;
-    /** @hide */
-    public static final int DATA_LOADER_NOT_READY =
-            IDataLoaderStatusListener.DATA_LOADER_NOT_READY;
-    /** @hide */
-    public static final int DATA_LOADER_RUNNING =
-            IDataLoaderStatusListener.DATA_LOADER_RUNNING;
-    /** @hide */
-    public static final int DATA_LOADER_STOPPED =
-            IDataLoaderStatusListener.DATA_LOADER_STOPPED;
-    /** @hide */
-    public static final int DATA_LOADER_SLOW_CONNECTION =
-            IDataLoaderStatusListener.DATA_LOADER_SLOW_CONNECTION;
-    /** @hide */
-    public static final int DATA_LOADER_NO_CONNECTION =
-            IDataLoaderStatusListener.DATA_LOADER_NO_CONNECTION;
-    /** @hide */
-    public static final int DATA_LOADER_CONNECTION_OK =
-            IDataLoaderStatusListener.DATA_LOADER_CONNECTION_OK;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"DATA_LOADER_"}, value = {
-            DATA_LOADER_READY,
-            DATA_LOADER_NOT_READY,
-            DATA_LOADER_RUNNING,
-            DATA_LOADER_STOPPED,
-            DATA_LOADER_SLOW_CONNECTION,
-            DATA_LOADER_NO_CONNECTION,
-            DATA_LOADER_CONNECTION_OK
-    })
-    public @interface DataLoaderStatus {
-    }
-
     /**
-     * Managed DataLoader interface. Each instance corresponds to a single Incremental File System
-     * instance.
+     * Managed DataLoader interface. Each instance corresponds to a single installation session.
      * @hide
      */
-    public abstract static class DataLoader {
+    public interface DataLoader {
         /**
-         * A virtual constructor used to do simple initialization. Not ready to serve any data yet.
-         * All heavy-lifting has to be done in onStart.
+         * A virtual constructor.
          *
-         * @param params    Data loader configuration parameters.
-         * @param connector IncFS API wrapper.
-         * @param listener  Used for reporting internal state to IncrementalService.
+         * @param dataLoaderParams parameters set in the installation session
+         * @param connector FS API wrapper
          * @return True if initialization of a Data Loader was successful. False will be reported to
-         * IncrementalService and can cause an unmount of an IFS instance.
+         * PackageManager and fail the installation
          */
-        public abstract boolean onCreate(@NonNull DataLoaderParams params,
-                @NonNull FileSystemConnector connector,
-                @NonNull StatusListener listener);
+        boolean onCreate(@NonNull DataLoaderParams dataLoaderParams,
+                @NonNull FileSystemConnector connector);
 
         /**
-         * Start the data loader. After this method returns data loader is considered to be ready to
-         * receive callbacks from IFS, supply data via connector and send status updates via
-         * callbacks.
+         * Prepare installation image. After this method succeeds installer will validate the files
+         * and continue installation.
          *
-         * @return True if Data Loader was able to start. False will be reported to
-         * IncrementalService and can cause an unmount of an IFS instance.
+         * @param addedFiles   list of files created in this installation session.
+         * @param removedFiles list of files removed in this installation session.
+         * @return false if unable to create and populate all addedFiles.
          */
-        public abstract boolean onStart();
-
-        /**
-         * Stop the data loader. Use to stop any additional threads and free up resources. Data
-         * loader is not longer responsible for supplying data. Start/Stop pair can be called
-         * multiple times e.g. if IFS detects corruption and data needs to be re-loaded.
-         */
-        public abstract void onStop();
-
-        /**
-         * Virtual destructor. Use to cleanup all internal state. After this method returns, the
-         * data loader can no longer use connector or callbacks. For any additional operations with
-         * this instance of IFS a new DataLoader will be created using createDataLoader method.
-         */
-        public abstract void onDestroy();
+        boolean onPrepareImage(Collection<InstallationFile> addedFiles,
+                Collection<String> removedFiles);
     }
 
     /**
@@ -145,7 +88,9 @@
      * @return An instance of a DataLoader.
      * @hide
      */
-    public abstract @Nullable DataLoader onCreateDataLoader();
+    public @Nullable DataLoader onCreateDataLoader() {
+        return null;
+    }
 
     /**
      * @hide
@@ -160,148 +105,125 @@
         @Override
         public void create(int id, @NonNull Bundle options,
                 @NonNull IDataLoaderStatusListener listener)
-                    throws IllegalArgumentException, RuntimeException {
+                throws IllegalArgumentException, RuntimeException {
             mId = id;
-            final DataLoaderParamsParcel params =  options.getParcelable("params");
+            final DataLoaderParamsParcel params = options.getParcelable("params");
             if (params == null) {
-                throw new IllegalArgumentException("Must specify Incremental data loader params");
+                throw new IllegalArgumentException("Must specify data loader params");
             }
-            final FileSystemControlParcel control =
-                    options.getParcelable("control");
+            final FileSystemControlParcel control = options.getParcelable("control");
             if (control == null) {
-                throw new IllegalArgumentException("Must specify Incremental control parcel");
+                throw new IllegalArgumentException("Must specify control parcel");
             }
-            mStatusListener = listener;
             try {
                 if (!nativeCreateDataLoader(id, control, params, listener)) {
                     Slog.e(TAG, "Failed to create native loader for " + mId);
                 }
             } catch (Exception ex) {
+                Slog.e(TAG, "Failed to create native loader for " + mId, ex);
                 destroy();
                 throw new RuntimeException(ex);
             } finally {
                 // Closing FDs.
-                if (control.incremental.cmd != null) {
-                    try {
-                        control.incremental.cmd.close();
-                    } catch (IOException e) {
-                        Slog.e(TAG, "Failed to close IncFs CMD file descriptor " + e);
+                if (control.incremental != null) {
+                    if (control.incremental.cmd != null) {
+                        try {
+                            control.incremental.cmd.close();
+                        } catch (IOException e) {
+                            Slog.e(TAG, "Failed to close IncFs CMD file descriptor " + e);
+                        }
+                    }
+                    if (control.incremental.log != null) {
+                        try {
+                            control.incremental.log.close();
+                        } catch (IOException e) {
+                            Slog.e(TAG, "Failed to close IncFs LOG file descriptor " + e);
+                        }
                     }
                 }
-                if (control.incremental.log != null) {
-                    try {
-                        control.incremental.log.close();
-                    } catch (IOException e) {
-                        Slog.e(TAG, "Failed to close IncFs LOG file descriptor " + e);
-                    }
-                }
-                NamedParcelFileDescriptor[] fds = params.dynamicArgs;
-                for (NamedParcelFileDescriptor nfd : fds) {
-                    try {
-                        nfd.fd.close();
-                    } catch (IOException e) {
-                        Slog.e(TAG,
-                                "Failed to close DynamicArgs parcel file descriptor " + e);
+                if (params.dynamicArgs != null) {
+                    NamedParcelFileDescriptor[] fds = params.dynamicArgs;
+                    for (NamedParcelFileDescriptor nfd : fds) {
+                        try {
+                            nfd.fd.close();
+                        } catch (IOException e) {
+                            Slog.e(TAG, "Failed to close DynamicArgs parcel file descriptor " + e);
+                        }
                     }
                 }
             }
         }
 
         @Override
-        public void start(List<InstallationFile> fileInfos) {
+        public void start() {
             if (!nativeStartDataLoader(mId)) {
-                Slog.e(TAG, "Failed to start loader: loader not found for " + mId);
+                Slog.e(TAG, "Failed to start loader: " + mId);
             }
         }
 
         @Override
         public void stop() {
             if (!nativeStopDataLoader(mId)) {
-                Slog.w(TAG, "Failed to stop loader: loader not found for " + mId);
+                Slog.w(TAG, "Failed to stop loader: " + mId);
             }
         }
 
         @Override
         public void destroy() {
             if (!nativeDestroyDataLoader(mId)) {
-                Slog.w(TAG, "Failed to destroy loader: loader not found for " + mId);
+                Slog.w(TAG, "Failed to destroy loader: " + mId);
+            }
+        }
+
+        @Override
+        public void prepareImage(List<InstallationFile> addedFiles, List<String> removedFiles) {
+            if (!nativePrepareImage(mId, addedFiles, removedFiles)) {
+                Slog.w(TAG, "Failed to destroy loader: " + mId);
             }
         }
     }
 
     /**
-     *
      * Used by the DataLoaderService implementations.
      *
      * @hide
      */
     public static final class FileSystemConnector {
         /**
-         * Creates a wrapper for an installation session connector.
+         * Create a wrapper for a native instance.
+         *
          * @hide
          */
-        FileSystemConnector(IPackageInstallerSessionFileSystemConnector connector) {
-            mConnector = connector;
+        FileSystemConnector(long nativeInstance) {
+            mNativeInstance = nativeInstance;
         }
 
         /**
          * Write data to an installation file from an arbitrary FD.
          *
-         * @param name name of file previously added to the installation session.
-         * @param offsetBytes offset into the file to begin writing at, or 0 to
-         *            start at the beginning of the file.
-         * @param lengthBytes total size of the file being written, used to
-         *            preallocate the underlying disk space, or -1 if unknown.
-         *            The system may clear various caches as needed to allocate
-         *            this space.
-         * @param incomingFd FD to read bytes from.
-         * @throws IOException if trouble opening the file for writing, such as
-         *             lack of disk space or unavailable media.
+         * @param name        name of file previously added to the installation session.
+         * @param offsetBytes offset into the file to begin writing at, or 0 to start at the
+         *                    beginning of the file.
+         * @param lengthBytes total size of the file being written, used to preallocate the
+         *                    underlying disk space, or -1 if unknown. The system may clear various
+         *                    caches as needed to allocate this space.
+         * @param incomingFd  FD to read bytes from.
+         * @throws IOException if trouble opening the file for writing, such as lack of disk space
+         *                     or unavailable media.
          */
         public void writeData(String name, long offsetBytes, long lengthBytes,
                 ParcelFileDescriptor incomingFd) throws IOException {
             try {
-                mConnector.writeData(name, offsetBytes, lengthBytes, incomingFd);
+                nativeWriteData(mNativeInstance, name, offsetBytes, lengthBytes, incomingFd);
             } catch (RuntimeException e) {
                 ExceptionUtils.maybeUnwrapIOException(e);
                 throw e;
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
             }
         }
 
-        private final IPackageInstallerSessionFileSystemConnector mConnector;
-    }
-
-    /**
-     * Wrapper for native reporting DataLoader statuses.
-     * @hide
-     */
-    public static final class StatusListener {
-        /**
-         * Creates a wrapper for a native instance.
-         * @hide
-         */
-        StatusListener(long nativeInstance) {
-            mNativeInstance = nativeInstance;
-        }
-
-        /**
-         * Report the status of DataLoader. Used for system-wide notifications e.g., disabling
-         * applications which rely on this data loader to function properly.
-         *
-         * @param status status to report.
-         * @return True if status was reported successfully.
-         */
-        public boolean onStatusChanged(@DataLoaderStatus int status) {
-            return nativeReportStatus(mNativeInstance, status);
-        }
-
         private final long mNativeInstance;
     }
 
-    private IDataLoaderStatusListener mStatusListener = null;
-
     /* Native methods */
     private native boolean nativeCreateDataLoader(int storageId,
             @NonNull FileSystemControlParcel control,
@@ -314,5 +236,10 @@
 
     private native boolean nativeDestroyDataLoader(int storageId);
 
-    private static native boolean nativeReportStatus(long nativeInstance, int status);
+    private native boolean nativePrepareImage(int storageId,
+            Collection<InstallationFile> addedFiles, Collection<String> removedFiles);
+
+    private static native void nativeWriteData(long nativeInstance, String name, long offsetBytes,
+            long lengthBytes, ParcelFileDescriptor incomingFd);
+
 }
diff --git a/core/jni/android_service_DataLoaderService.cpp b/core/jni/android_service_DataLoaderService.cpp
index 381b386..a62d127 100644
--- a/core/jni/android_service_DataLoaderService.cpp
+++ b/core/jni/android_service_DataLoaderService.cpp
@@ -51,13 +51,19 @@
 }
 
 
-static jboolean nativeReportStatus(JNIEnv* env,
-                                   jobject clazz,
-                                   jlong self,
-                                   jint status) {
-    auto listener = (DataLoaderStatusListenerPtr)self;
-    return DataLoader_StatusListener_reportStatus(listener,
-                     (DataLoaderStatus)status);
+static jboolean nativePrepareImage(JNIEnv* env, jobject thiz, jint storageId, jobject addedFiles, jobject removedFiles) {
+    return DataLoaderService_OnPrepareImage(storageId, addedFiles, removedFiles);
+}
+
+static void nativeWriteData(JNIEnv* env,
+                            jobject clazz,
+                            jlong self,
+                            jstring name,
+                            jlong offsetBytes,
+                            jlong lengthBytes,
+                            jobject incomingFd) {
+    auto connector = (DataLoaderFilesystemConnectorPtr)self;
+    return DataLoader_FilesystemConnector_writeData(connector, name, offsetBytes, lengthBytes, incomingFd);
 }
 
 static const JNINativeMethod dlc_method_table[] = {
@@ -69,7 +75,8 @@
         {"nativeStartDataLoader", "(I)Z", (void*)nativeStartDataLoader},
         {"nativeStopDataLoader", "(I)Z", (void*)nativeStopDataLoader},
         {"nativeDestroyDataLoader", "(I)Z", (void*)nativeDestroyDataLoader},
-        {"nativeReportStatus", "(JI)Z", (void*)nativeReportStatus},
+        {"nativePrepareImage", "(ILjava/util/Collection;Ljava/util/Collection;)Z", (void*)nativePrepareImage},
+        {"nativeWriteData", "(JLjava/lang/String;JJLandroid/os/ParcelFileDescriptor;)V", (void*)nativeWriteData},
 };
 
 }  // namespace
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1165d2d..44a902c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4113,7 +4113,7 @@
     <permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Must be required by intent filter verifier receiver, to ensure that only the
+    <!-- Must be required by intent filter verifier rintent-filtereceiver, to ensure that only the
          system can interact with it.
          @hide
     -->
@@ -5143,6 +5143,12 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
-</application>
+        <service android:name="com.android.server.pm.PackageManagerShellCommandDataLoader">
+            <intent-filter>
+                <action android:name="android.intent.action.LOAD_DATA" />
+            </intent-filter>
+        </service>
+
+    </application>
 
 </manifest>