diff options
Diffstat (limited to 'core/java/android')
8 files changed, 199 insertions, 211 deletions
diff --git a/core/java/android/content/pm/DataLoaderParams.java b/core/java/android/content/pm/DataLoaderParams.java index af4b99a5f815..60d7bb3c5918 100644 --- a/core/java/android/content/pm/DataLoaderParams.java +++ b/core/java/android/content/pm/DataLoaderParams.java @@ -19,6 +19,7 @@ package android.content.pm; 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.Map; 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 @@ import java.util.stream.Collectors; */ @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 @@ public class DataLoaderParams { mData = data; } - /** - * @hide - */ - public DataLoaderParams(@NonNull DataLoaderParamsParcel data) { + /** @hide */ + DataLoaderParams(@NonNull DataLoaderParamsParcel data) { mData = data; } + /** @hide */ + public final @NonNull DataLoaderParamsParcel getData() { + return mData; + } + /** - * @return static server's URL + * @return data loader type */ - public final @NonNull String getStaticArgs() { - return mData.staticArgs; + public final @NonNull @DataLoaderType int getType() { + return mData.type; } /** - * @return data loader's package name + * @return data loader's component name */ - public final @NonNull String getPackageName() { - return mData.packageName; + public final @NonNull ComponentName getComponentName() { + return new ComponentName(mData.packageName, mData.className); } /** - * @hide + * @return data loader's arguments */ - public final @NonNull DataLoaderParamsParcel getData() { - return mData; + public final @NonNull String getArguments() { + return mData.arguments; } /** - * @return data loader's dynamic arguments such as file descriptors + * @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 33163980b915..e05843b4d4e9 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 @@ import android.content.pm.NamedParcelFileDescriptor; * @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 000000000000..7d726f5ddd6f --- /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 c65bd6acbaf8..b5baa9379d16 100644 --- a/core/java/android/content/pm/IDataLoader.aidl +++ b/core/java/android/content/pm/IDataLoader.aidl @@ -27,7 +27,9 @@ import java.util.List; */ 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 a60d6ee2d28a..5011faafa2f7 100644 --- a/core/java/android/content/pm/IDataLoaderStatusListener.aidl +++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl @@ -22,13 +22,18 @@ package android.content.pm; */ 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 3d6d849bf03d..e4a0bc0197a1 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1461,10 +1461,7 @@ public class PackageInstaller { /** {@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 @@ public class PackageInstaller { 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 @@ public class PackageInstaller { 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 @@ public class PackageInstaller { } /** - * 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 @@ public class PackageInstaller { 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 @@ public class PackageInstaller { 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 fb94fc9bd719..2138d553102e 100644 --- a/core/java/android/os/incremental/IncrementalFileStorages.java +++ b/core/java/android/os/incremental/IncrementalFileStorages.java @@ -87,8 +87,8 @@ public final class IncrementalFileStorages { 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 54a4fa6023a1..75f252e23f79 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.DataLoaderParamsParcel; 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 @@ import java.util.List; */ @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. - */ - 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. + * @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 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 @@ public abstract class DataLoaderService extends Service { * @return An instance of a DataLoader. * @hide */ - public abstract @Nullable DataLoader onCreateDataLoader(); + public @Nullable DataLoader onCreateDataLoader() { + return null; + } /** * @hide @@ -160,148 +105,125 @@ public abstract class DataLoaderService extends Service { @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 @@ public abstract class DataLoaderService extends Service { 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); + } |
