Loading core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -11876,6 +11876,7 @@ package android.content.pm { public class PackageInstaller { method public void abandonSession(int); method public void checkInstallConstraints(@NonNull java.util.List<java.lang.String>, @NonNull android.content.pm.PackageInstaller.InstallConstraints, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.content.pm.PackageInstaller.InstallConstraintsResult>); method public void commitSessionAfterInstallConstraintsAreMet(int, @NonNull android.content.IntentSender, @NonNull android.content.pm.PackageInstaller.InstallConstraints, long); method public int createSession(@NonNull android.content.pm.PackageInstaller.SessionParams) throws java.io.IOException; method @Deprecated @Nullable public android.content.pm.PackageInstaller.SessionInfo getActiveStagedSession(); method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getActiveStagedSessions(); Loading Loading @@ -11920,6 +11921,7 @@ package android.content.pm { field public static final int STATUS_FAILURE_INCOMPATIBLE = 7; // 0x7 field public static final int STATUS_FAILURE_INVALID = 4; // 0x4 field public static final int STATUS_FAILURE_STORAGE = 6; // 0x6 field public static final int STATUS_FAILURE_TIMEOUT = 8; // 0x8 field public static final int STATUS_PENDING_USER_ACTION = -1; // 0xffffffff field public static final int STATUS_SUCCESS = 0; // 0x0 } core/java/android/content/pm/IPackageInstallerSession.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ interface IPackageInstallerSession { void commit(in IntentSender statusReceiver, boolean forTransferred); void transfer(in String packageName); void abandon(); void seal(); List<String> fetchPackageNames(); DataLoaderParamsParcel getDataLoaderParams(); void addFile(int location, String name, long lengthBytes, in byte[] metadata, in byte[] signature); Loading core/java/android/content/pm/PackageInstaller.java +69 −2 Original line number Diff line number Diff line Loading @@ -44,8 +44,11 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.AppGlobals; import android.compat.annotation.UnsupportedAppUsage; import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager.DeleteFlags; Loading @@ -59,9 +62,11 @@ import android.graphics.Bitmap; import android.icu.util.ULocale; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.FileBridge; import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; Loading Loading @@ -226,8 +231,8 @@ public class PackageInstaller { * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS}, * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED}, * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT}, * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or * {@link #STATUS_FAILURE_STORAGE}. * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, * {@link #STATUS_FAILURE_STORAGE}, or {@link #STATUS_FAILURE_TIMEOUT}. * <p> * More information about a status may be available through additional * extras; see the individual status documentation for details. Loading Loading @@ -440,6 +445,13 @@ public class PackageInstaller { */ public static final int STATUS_FAILURE_INCOMPATIBLE = 7; /** * The operation failed because it didn't complete within the specified timeout. * * @see #EXTRA_STATUS_MESSAGE */ public static final int STATUS_FAILURE_TIMEOUT = 8; /** * Default value, non-streaming installation session. * Loading Loading @@ -1015,6 +1027,61 @@ public class PackageInstaller { } } /** * Commit the session when all constraints are satisfied. This is a convenient method to * combine {@link #waitForInstallConstraints(List, InstallConstraints, IntentSender, long)} * and {@link Session#commit(IntentSender)}. * <p> * Once this method is called, the session is sealed and no additional mutations * may be performed on the session. In the case of timeout, you may commit the * session again using this method or {@link Session#commit(IntentSender)} for retries. * * @param statusReceiver Called when the state of the session changes. Intents * sent to this receiver contain {@link #EXTRA_STATUS}. * Refer to the individual status codes on how to handle them. * @param constraints The requirements to satisfy before committing the session. * @param timeoutMillis The maximum time to wait, in milliseconds until the * constraints are satisfied. The caller will be notified via * {@code statusReceiver} if timeout happens before commit. */ public void commitSessionAfterInstallConstraintsAreMet(int sessionId, @NonNull IntentSender statusReceiver, @NonNull InstallConstraints constraints, @DurationMillisLong long timeoutMillis) { try { var session = mInstaller.openSession(sessionId); session.seal(); var packageNames = session.fetchPackageNames(); var intentSender = new IntentSender((IIntentSender) new IIntentSender.Stub() { @Override public void send(int code, Intent intent, String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { var result = intent.getParcelableExtra( PackageInstaller.EXTRA_INSTALL_CONSTRAINTS_RESULT, InstallConstraintsResult.class); try { if (result.isAllConstraintsSatisfied()) { session.commit(statusReceiver, false); } else { // timeout final Intent fillIn = new Intent(); fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); fillIn.putExtra(PackageInstaller.EXTRA_STATUS, STATUS_FAILURE_TIMEOUT); fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, "Install constraints not satisfied within timeout"); statusReceiver.sendIntent( ActivityThread.currentApplication(), 0, fillIn, null, null); } } catch (Exception ignore) { } } }); waitForInstallConstraints(packageNames, constraints, intentSender, timeoutMillis); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Events for observing session lifecycle. * <p> Loading services/core/java/com/android/server/pm/PackageInstallerSession.java +59 −0 Original line number Diff line number Diff line Loading @@ -1842,6 +1842,60 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { dispatchSessionSealed(); } @Override public void seal() { assertNotChild("seal"); assertCallerIsOwnerOrRoot(); try { sealInternal(); for (var child : getChildSessions()) { child.sealInternal(); } } catch (PackageManagerException e) { throw new IllegalStateException("Package is not valid", e); } } private void sealInternal() throws PackageManagerException { synchronized (mLock) { sealLocked(); } } @Override public List<String> fetchPackageNames() { assertNotChild("fetchPackageNames"); assertCallerIsOwnerOrRoot(); var sessions = getSelfOrChildSessions(); var result = new ArrayList<String>(sessions.size()); for (var s : sessions) { result.add(s.fetchPackageName()); } return result; } private String fetchPackageName() { assertSealed("fetchPackageName"); synchronized (mLock) { final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final List<File> addedFiles = getAddedApksLocked(); for (File addedFile : addedFiles) { final ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(), addedFile, 0); if (result.isError()) { throw new IllegalStateException( "Can't parse package for session=" + sessionId, result.getException()); } final ApkLite apk = result.getResult(); var packageName = apk.getPackageName(); if (packageName != null) { return packageName; } } throw new IllegalStateException("Can't fetch package name for session=" + sessionId); } } /** * Kicks off the install flow. The first step is to persist 'sealed' flags * to prevent mutations of hard links created later. Loading Loading @@ -2095,6 +2149,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } @NonNull private List<PackageInstallerSession> getSelfOrChildSessions() { return isMultiPackage() ? getChildSessions() : Collections.singletonList(this); } /** * Seal the session to prevent further modification. * Loading Loading
core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -11876,6 +11876,7 @@ package android.content.pm { public class PackageInstaller { method public void abandonSession(int); method public void checkInstallConstraints(@NonNull java.util.List<java.lang.String>, @NonNull android.content.pm.PackageInstaller.InstallConstraints, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.content.pm.PackageInstaller.InstallConstraintsResult>); method public void commitSessionAfterInstallConstraintsAreMet(int, @NonNull android.content.IntentSender, @NonNull android.content.pm.PackageInstaller.InstallConstraints, long); method public int createSession(@NonNull android.content.pm.PackageInstaller.SessionParams) throws java.io.IOException; method @Deprecated @Nullable public android.content.pm.PackageInstaller.SessionInfo getActiveStagedSession(); method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getActiveStagedSessions(); Loading Loading @@ -11920,6 +11921,7 @@ package android.content.pm { field public static final int STATUS_FAILURE_INCOMPATIBLE = 7; // 0x7 field public static final int STATUS_FAILURE_INVALID = 4; // 0x4 field public static final int STATUS_FAILURE_STORAGE = 6; // 0x6 field public static final int STATUS_FAILURE_TIMEOUT = 8; // 0x8 field public static final int STATUS_PENDING_USER_ACTION = -1; // 0xffffffff field public static final int STATUS_SUCCESS = 0; // 0x0 }
core/java/android/content/pm/IPackageInstallerSession.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ interface IPackageInstallerSession { void commit(in IntentSender statusReceiver, boolean forTransferred); void transfer(in String packageName); void abandon(); void seal(); List<String> fetchPackageNames(); DataLoaderParamsParcel getDataLoaderParams(); void addFile(int location, String name, long lengthBytes, in byte[] metadata, in byte[] signature); Loading
core/java/android/content/pm/PackageInstaller.java +69 −2 Original line number Diff line number Diff line Loading @@ -44,8 +44,11 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.AppGlobals; import android.compat.annotation.UnsupportedAppUsage; import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager.DeleteFlags; Loading @@ -59,9 +62,11 @@ import android.graphics.Bitmap; import android.icu.util.ULocale; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.FileBridge; import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; Loading Loading @@ -226,8 +231,8 @@ public class PackageInstaller { * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS}, * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED}, * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT}, * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or * {@link #STATUS_FAILURE_STORAGE}. * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, * {@link #STATUS_FAILURE_STORAGE}, or {@link #STATUS_FAILURE_TIMEOUT}. * <p> * More information about a status may be available through additional * extras; see the individual status documentation for details. Loading Loading @@ -440,6 +445,13 @@ public class PackageInstaller { */ public static final int STATUS_FAILURE_INCOMPATIBLE = 7; /** * The operation failed because it didn't complete within the specified timeout. * * @see #EXTRA_STATUS_MESSAGE */ public static final int STATUS_FAILURE_TIMEOUT = 8; /** * Default value, non-streaming installation session. * Loading Loading @@ -1015,6 +1027,61 @@ public class PackageInstaller { } } /** * Commit the session when all constraints are satisfied. This is a convenient method to * combine {@link #waitForInstallConstraints(List, InstallConstraints, IntentSender, long)} * and {@link Session#commit(IntentSender)}. * <p> * Once this method is called, the session is sealed and no additional mutations * may be performed on the session. In the case of timeout, you may commit the * session again using this method or {@link Session#commit(IntentSender)} for retries. * * @param statusReceiver Called when the state of the session changes. Intents * sent to this receiver contain {@link #EXTRA_STATUS}. * Refer to the individual status codes on how to handle them. * @param constraints The requirements to satisfy before committing the session. * @param timeoutMillis The maximum time to wait, in milliseconds until the * constraints are satisfied. The caller will be notified via * {@code statusReceiver} if timeout happens before commit. */ public void commitSessionAfterInstallConstraintsAreMet(int sessionId, @NonNull IntentSender statusReceiver, @NonNull InstallConstraints constraints, @DurationMillisLong long timeoutMillis) { try { var session = mInstaller.openSession(sessionId); session.seal(); var packageNames = session.fetchPackageNames(); var intentSender = new IntentSender((IIntentSender) new IIntentSender.Stub() { @Override public void send(int code, Intent intent, String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { var result = intent.getParcelableExtra( PackageInstaller.EXTRA_INSTALL_CONSTRAINTS_RESULT, InstallConstraintsResult.class); try { if (result.isAllConstraintsSatisfied()) { session.commit(statusReceiver, false); } else { // timeout final Intent fillIn = new Intent(); fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); fillIn.putExtra(PackageInstaller.EXTRA_STATUS, STATUS_FAILURE_TIMEOUT); fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, "Install constraints not satisfied within timeout"); statusReceiver.sendIntent( ActivityThread.currentApplication(), 0, fillIn, null, null); } } catch (Exception ignore) { } } }); waitForInstallConstraints(packageNames, constraints, intentSender, timeoutMillis); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Events for observing session lifecycle. * <p> Loading
services/core/java/com/android/server/pm/PackageInstallerSession.java +59 −0 Original line number Diff line number Diff line Loading @@ -1842,6 +1842,60 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { dispatchSessionSealed(); } @Override public void seal() { assertNotChild("seal"); assertCallerIsOwnerOrRoot(); try { sealInternal(); for (var child : getChildSessions()) { child.sealInternal(); } } catch (PackageManagerException e) { throw new IllegalStateException("Package is not valid", e); } } private void sealInternal() throws PackageManagerException { synchronized (mLock) { sealLocked(); } } @Override public List<String> fetchPackageNames() { assertNotChild("fetchPackageNames"); assertCallerIsOwnerOrRoot(); var sessions = getSelfOrChildSessions(); var result = new ArrayList<String>(sessions.size()); for (var s : sessions) { result.add(s.fetchPackageName()); } return result; } private String fetchPackageName() { assertSealed("fetchPackageName"); synchronized (mLock) { final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final List<File> addedFiles = getAddedApksLocked(); for (File addedFile : addedFiles) { final ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(), addedFile, 0); if (result.isError()) { throw new IllegalStateException( "Can't parse package for session=" + sessionId, result.getException()); } final ApkLite apk = result.getResult(); var packageName = apk.getPackageName(); if (packageName != null) { return packageName; } } throw new IllegalStateException("Can't fetch package name for session=" + sessionId); } } /** * Kicks off the install flow. The first step is to persist 'sealed' flags * to prevent mutations of hard links created later. Loading Loading @@ -2095,6 +2149,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } @NonNull private List<PackageInstallerSession> getSelfOrChildSessions() { return isMultiPackage() ? getChildSessions() : Collections.singletonList(this); } /** * Seal the session to prevent further modification. * Loading