summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorPhilip P. Moltmann <moltmann@google.com>2017-07-19 10:06:14 -0700
committerPhilip P. Moltmann <moltmann@google.com>2017-08-07 10:50:57 -0700
commit94deaf7725c418ec1950d810ab86f0d157ddf518 (patch)
tree476cf9ae1f932fc5330547401b5947ed2c307e85 /core/java/android
parent27106b97b3db88a2460b582fa61b5acc8c30fdd1 (diff)
Allow to transfer+seal a install session
... so that one package can supply the data and another one can issue the commit. Also allow reading of sealed sessions. Also lock more in PackageInstallerSession so that we can be sure the session is not used by the old package anymore once transferred and that all calls into the session work on consistent data. Bug: 37281396 Test: cts-tradefed run cts-dev -m CtsContentTestCases --test=android.content.pm.cts.InstallSessionTransferTest Installed and uninstalled packages via the PackageInstaller app Installed and uninstalled packages via the Google Play Store Change-Id: Id4b7a0071d703b7d18c9f5bf2bd15ebf67086d07
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/content/pm/IPackageInstallerSession.aidl3
-rw-r--r--core/java/android/content/pm/PackageInstaller.java66
2 files changed, 66 insertions, 3 deletions
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 2a3fac341e24..0b16852246f8 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -32,6 +32,7 @@ interface IPackageInstallerSession {
void removeSplit(String splitName);
void close();
- void commit(in IntentSender statusReceiver);
+ void commit(in IntentSender statusReceiver, boolean forTransferred);
+ void transfer(in String packageName);
void abandon();
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index c3ebf554ea8c..38b34872d2fa 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -38,6 +38,7 @@ import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
+import android.os.ParcelableException;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.system.ErrnoException;
@@ -793,7 +794,7 @@ public class PackageInstaller {
* @throws IOException if trouble opening the file for writing, such as
* lack of disk space or unavailable media.
* @throws SecurityException if called after the session has been
- * committed or abandoned.
+ * sealed or abandoned
*/
public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes,
long lengthBytes) throws IOException {
@@ -918,7 +919,68 @@ public class PackageInstaller {
*/
public void commit(@NonNull IntentSender statusReceiver) {
try {
- mSession.commit(statusReceiver);
+ mSession.commit(statusReceiver, false);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Attempt to commit a session that has been {@link #transfer(String) transferred}.
+ *
+ * <p>If the device reboots before the session has been finalized, you may commit the
+ * session again.
+ *
+ * <p>The caller of this method is responsible to ensure the safety of the session. As the
+ * session was created by another - usually less trusted - app, it is paramount that before
+ * committing <u>all</u> public and system {@link SessionInfo properties of the session}
+ * and <u>all</u> {@link #openRead(String) APKs} are verified by the caller. It might happen
+ * that new properties are added to the session with a new API revision. In this case the
+ * callers need to be updated.
+ *
+ * @param statusReceiver Callbacks called when the state of the session changes.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
+ public void commitTransferred(@NonNull IntentSender statusReceiver) {
+ try {
+ mSession.commit(statusReceiver, true);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Transfer the session to a new owner.
+ * <p>
+ * Only sessions that update the installing app can be transferred.
+ * <p>
+ * After the transfer to a package with a different uid all method calls on the session
+ * will cause {@link SecurityException}s.
+ * <p>
+ * Once this method is called, the session is sealed and no additional mutations beside
+ * committing it may be performed on the session.
+ *
+ * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES
+ * permission.
+ *
+ * @throws PackageManager.NameNotFoundException if the new owner could not be found.
+ * @throws SecurityException if called after the session has been committed or abandoned.
+ * @throws SecurityException if the session does not update the original installer
+ * @throws SecurityException if streams opened through
+ * {@link #openWrite(String, long, long) are still open.
+ */
+ public void transfer(@NonNull String packageName)
+ throws PackageManager.NameNotFoundException {
+ Preconditions.checkNotNull(packageName);
+
+ try {
+ mSession.transfer(packageName);
+ } catch (ParcelableException e) {
+ e.maybeRethrow(PackageManager.NameNotFoundException.class);
+ throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}