diff options
Diffstat (limited to 'core/java/android')
4 files changed, 119 insertions, 66 deletions
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl index 7db5a80b6cf9..3fbc28402405 100644 --- a/core/java/android/os/incremental/IIncrementalService.aidl +++ b/core/java/android/os/incremental/IIncrementalService.aidl @@ -38,14 +38,20 @@ interface IIncrementalService { * Opens or creates a storage given a target path and data loader params. Returns the storage ID. */ int openStorage(in @utf8InCpp String path); - int createStorage(in @utf8InCpp String path, in DataLoaderParamsParcel params, int createMode, - in IDataLoaderStatusListener statusListener, - in StorageHealthCheckParams healthCheckParams, - in IStorageHealthListener healthListener, - in PerUidReadTimeouts[] perUidReadTimeouts); + int createStorage(in @utf8InCpp String path, in DataLoaderParamsParcel params, int createMode); int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode); /** + * Loops DataLoader through bind/create/start with params. + */ + boolean startLoading(int storageId, + in DataLoaderParamsParcel params, + in IDataLoaderStatusListener statusListener, + in StorageHealthCheckParams healthCheckParams, + in IStorageHealthListener healthListener, + in PerUidReadTimeouts[] perUidReadTimeouts); + + /** * Bind-mounts a path under a storage to a full path. Can be permanent or temporary. */ const int BIND_TEMPORARY = 0; @@ -101,6 +107,14 @@ interface IIncrementalService { int isFileFullyLoaded(int storageId, in @utf8InCpp String path); /** + * Checks if all files in the storage are fully loaded. + * 0 - fully loaded + * >0 - certain pages missing + * <0 - -errcode + */ + int isFullyLoaded(int storageId); + + /** * Returns overall loading progress of all the files on a storage, progress value between [0,1]. * Returns a negative value on error. */ @@ -113,11 +127,6 @@ interface IIncrementalService { byte[] getMetadataById(int storageId, in byte[] fileId); /** - * Starts loading data for a storage. - */ - boolean startLoading(int storageId); - - /** * Deletes a storage given its ID. Deletes its bind mounts and unmount it. Stop its data loader. */ void deleteStorage(int storageId); diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java index 59292baa110c..f2fe71913bb1 100644 --- a/core/java/android/os/incremental/IncrementalFileStorages.java +++ b/core/java/android/os/incremental/IncrementalFileStorages.java @@ -37,7 +37,6 @@ import android.content.Context; import android.content.pm.DataLoaderParams; import android.content.pm.IDataLoaderStatusListener; import android.content.pm.InstallationFileParcel; -import android.text.TextUtils; import java.io.File; import java.io.IOException; @@ -53,6 +52,7 @@ public final class IncrementalFileStorages { private @NonNull final IncrementalManager mIncrementalManager; private @NonNull final File mStageDir; + private @Nullable IncrementalStorage mInheritedStorage; private @Nullable IncrementalStorage mDefaultStorage; /** @@ -65,6 +65,7 @@ public final class IncrementalFileStorages { */ public static IncrementalFileStorages initialize(Context context, @NonNull File stageDir, + @Nullable File inheritedDir, @NonNull DataLoaderParams dataLoaderParams, @Nullable IDataLoaderStatusListener statusListener, @Nullable StorageHealthCheckParams healthCheckParams, @@ -79,9 +80,8 @@ public final class IncrementalFileStorages { throw new IOException("Failed to obtain incrementalManager."); } - final IncrementalFileStorages result = new IncrementalFileStorages(stageDir, - incrementalManager, dataLoaderParams, statusListener, healthCheckParams, - healthListener, perUidReadTimeouts); + final IncrementalFileStorages result = new IncrementalFileStorages(stageDir, inheritedDir, + incrementalManager, dataLoaderParams); for (InstallationFileParcel file : addedFiles) { if (file.location == LOCATION_DATA_APP) { try { @@ -95,43 +95,46 @@ public final class IncrementalFileStorages { throw new IOException("Unknown file location: " + file.location); } } - - result.startLoading(); + result.startLoading(dataLoaderParams, statusListener, healthCheckParams, healthListener, + perUidReadTimeouts); return result; } private IncrementalFileStorages(@NonNull File stageDir, + @Nullable File inheritedDir, @NonNull IncrementalManager incrementalManager, - @NonNull DataLoaderParams dataLoaderParams, - @Nullable IDataLoaderStatusListener statusListener, - @Nullable StorageHealthCheckParams healthCheckParams, - @Nullable IStorageHealthListener healthListener, - @NonNull PerUidReadTimeouts[] perUidReadTimeouts) throws IOException { + @NonNull DataLoaderParams dataLoaderParams) throws IOException { try { mStageDir = stageDir; mIncrementalManager = incrementalManager; - if (dataLoaderParams.getComponentName().getPackageName().equals("local")) { - final String incrementalPath = dataLoaderParams.getArguments(); - if (TextUtils.isEmpty(incrementalPath)) { - throw new IOException("Failed to create storage: incrementalPath is empty"); - } - mDefaultStorage = mIncrementalManager.openStorage(incrementalPath); - if (mDefaultStorage == null) { - throw new IOException( - "Couldn't open incremental storage at " + incrementalPath); - } - mDefaultStorage.bind(stageDir.getAbsolutePath()); - } else { - mDefaultStorage = mIncrementalManager.createStorage(stageDir.getAbsolutePath(), - dataLoaderParams, IncrementalManager.CREATE_MODE_CREATE - | IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false, - statusListener, healthCheckParams, healthListener, perUidReadTimeouts); - if (mDefaultStorage == null) { - throw new IOException( - "Couldn't create incremental storage at " + stageDir); + if (inheritedDir != null && IncrementalManager.isIncrementalPath( + inheritedDir.getAbsolutePath())) { + mInheritedStorage = mIncrementalManager.openStorage( + inheritedDir.getAbsolutePath()); + if (mInheritedStorage != null) { + if (!mInheritedStorage.isFullyLoaded()) { + throw new IOException("Inherited storage has missing pages."); + } + + mDefaultStorage = mIncrementalManager.createStorage(stageDir.getAbsolutePath(), + mInheritedStorage, IncrementalManager.CREATE_MODE_CREATE + | IncrementalManager.CREATE_MODE_TEMPORARY_BIND); + if (mDefaultStorage == null) { + throw new IOException( + "Couldn't create linked incremental storage at " + stageDir); + } + return; } } + + mDefaultStorage = mIncrementalManager.createStorage(stageDir.getAbsolutePath(), + dataLoaderParams, IncrementalManager.CREATE_MODE_CREATE + | IncrementalManager.CREATE_MODE_TEMPORARY_BIND); + if (mDefaultStorage == null) { + throw new IOException( + "Couldn't create incremental storage at " + stageDir); + } } catch (IOException e) { cleanUp(); throw e; @@ -149,9 +152,16 @@ public final class IncrementalFileStorages { /** * Starts or re-starts loading of data. */ - public void startLoading() throws IOException { - if (!mDefaultStorage.startLoading()) { - throw new IOException("Failed to start loading data for Incremental installation."); + void startLoading( + @NonNull DataLoaderParams dataLoaderParams, + @Nullable IDataLoaderStatusListener statusListener, + @Nullable StorageHealthCheckParams healthCheckParams, + @Nullable IStorageHealthListener healthListener, + @NonNull PerUidReadTimeouts[] perUidReadTimeouts) throws IOException { + if (!mDefaultStorage.startLoading(dataLoaderParams, statusListener, healthCheckParams, + healthListener, perUidReadTimeouts)) { + throw new IOException( + "Failed to start or restart loading data for Incremental installation."); } } @@ -163,6 +173,21 @@ public final class IncrementalFileStorages { } /** + * Creates a hardlink from inherited storage to default. + */ + public boolean makeLink(@NonNull String relativePath, @NonNull String fromBase, + @NonNull String toBase) throws IOException { + if (mInheritedStorage == null) { + return false; + } + final File sourcePath = new File(fromBase, relativePath); + final File destPath = new File(toBase, relativePath); + mInheritedStorage.makeLink(sourcePath.getAbsolutePath(), mDefaultStorage, + destPath.getAbsolutePath()); + return true; + } + + /** * Permanently disables readlogs. */ public void disallowReadLogs() { diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java index 4b9327021cb0..7e7057fe56cb 100644 --- a/core/java/android/os/incremental/IncrementalManager.java +++ b/core/java/android/os/incremental/IncrementalManager.java @@ -22,7 +22,6 @@ import android.annotation.Nullable; import android.annotation.SystemService; import android.content.Context; import android.content.pm.DataLoaderParams; -import android.content.pm.IDataLoaderStatusListener; import android.content.pm.IPackageLoadingProgressCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -95,32 +94,20 @@ public final class IncrementalManager { * @param params IncrementalDataLoaderParams object to configure data loading. * @param createMode Mode for opening an old Incremental File System mount or creating * a new mount. - * @param autoStartDataLoader Set true to immediately start data loader after creating storage. * @return IncrementalStorage object corresponding to the mounted directory. */ @Nullable public IncrementalStorage createStorage(@NonNull String path, @NonNull DataLoaderParams params, - @CreateMode int createMode, - boolean autoStartDataLoader, - @Nullable IDataLoaderStatusListener statusListener, - @Nullable StorageHealthCheckParams healthCheckParams, - @Nullable IStorageHealthListener healthListener, - @NonNull PerUidReadTimeouts[] perUidReadTimeouts) { + @CreateMode int createMode) { Objects.requireNonNull(path); Objects.requireNonNull(params); - Objects.requireNonNull(perUidReadTimeouts); try { - final int id = mService.createStorage(path, params.getData(), createMode, - statusListener, healthCheckParams, healthListener, perUidReadTimeouts); + final int id = mService.createStorage(path, params.getData(), createMode); if (id < 0) { return null; } - final IncrementalStorage storage = new IncrementalStorage(mService, id); - if (autoStartDataLoader) { - storage.startLoading(); - } - return storage; + return new IncrementalStorage(mService, id); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -281,15 +268,18 @@ public final class IncrementalManager { * Unbinds the target dir and deletes the corresponding storage instance. * Deletes the package name and associated storage id from maps. */ - public void onPackageRemoved(@NonNull String codePath) { + public void onPackageRemoved(@NonNull File codeFile) { try { + final String codePath = codeFile.getAbsolutePath(); final IncrementalStorage storage = openStorage(codePath); if (storage == null) { return; } mLoadingProgressCallbacks.cleanUpCallbacks(storage); unregisterHealthListener(codePath); - mService.deleteStorage(storage.getId()); + + // Parent since we bind-mount a folder one level above. + mService.deleteBindMount(storage.getId(), codeFile.getParent()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java index 5b688bbd0655..e6ce8cd56d28 100644 --- a/core/java/android/os/incremental/IncrementalStorage.java +++ b/core/java/android/os/incremental/IncrementalStorage.java @@ -18,11 +18,14 @@ package android.os.incremental; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.DataLoaderParams; +import android.content.pm.IDataLoaderStatusListener; import android.os.RemoteException; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.Objects; import java.util.UUID; /** @@ -323,6 +326,24 @@ public final class IncrementalStorage { } } + + /** + * Checks if all files in the storage are fully loaded. + */ + public boolean isFullyLoaded() throws IOException { + try { + final int res = mService.isFullyLoaded(mId); + if (res < 0) { + throw new IOException( + "isFullyLoaded() failed at querying loading progress, errno " + -res); + } + return res == 0; + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + return false; + } + } + /** * Returns the loading progress of a storage * @@ -376,13 +397,21 @@ public final class IncrementalStorage { } /** - * Informs the data loader service associated with the current storage to start data loader - * - * @return True if data loader is successfully started. + * Iinitializes and starts the DataLoader. + * This makes sure all install-time parameters are applied. + * Does not affect persistent DataLoader params. + * @return True if start request was successfully queued. */ - public boolean startLoading() { + public boolean startLoading( + @NonNull DataLoaderParams dataLoaderParams, + @Nullable IDataLoaderStatusListener statusListener, + @Nullable StorageHealthCheckParams healthCheckParams, + @Nullable IStorageHealthListener healthListener, + @NonNull PerUidReadTimeouts[] perUidReadTimeouts) { + Objects.requireNonNull(perUidReadTimeouts); try { - return mService.startLoading(mId); + return mService.startLoading(mId, dataLoaderParams.getData(), statusListener, + healthCheckParams, healthListener, perUidReadTimeouts); } catch (RemoteException e) { e.rethrowFromSystemServer(); return false; |
