diff --git a/api/current.txt b/api/current.txt index bdcc2ff8ac91f..0848a7a5d722e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -8544,36 +8544,6 @@ package android.content.pm { field public int reqGlEsVersion; } - public class InstallSessionInfo implements android.os.Parcelable { - method public int describeContents(); - method public android.graphics.Bitmap getAppIcon(); - method public java.lang.CharSequence getAppLabel(); - method public java.lang.String getAppPackageName(); - method public android.content.Intent getDetailsIntent(); - method public java.lang.String getInstallerPackageName(); - method public float getProgress(); - method public int getSessionId(); - method public boolean isOpen(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; - } - - public class InstallSessionParams implements android.os.Parcelable { - ctor public InstallSessionParams(int); - method public int describeContents(); - method public void setAppIcon(android.graphics.Bitmap); - method public void setAppLabel(java.lang.CharSequence); - method public void setAppPackageName(java.lang.String); - method public void setInstallLocation(int); - method public void setOriginatingUri(android.net.Uri); - method public void setReferrerUri(android.net.Uri); - method public void setSize(long); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; - field public static final int MODE_FULL_INSTALL = 1; // 0x1 - field public static final int MODE_INHERIT_EXISTING = 2; // 0x2 - } - public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { ctor public InstrumentationInfo(); ctor public InstrumentationInfo(android.content.pm.InstrumentationInfo); @@ -8675,37 +8645,35 @@ package android.content.pm { public class PackageInstaller { method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler); - method public int createSession(android.content.pm.InstallSessionParams) throws java.io.IOException; - method public java.util.List getAllSessions(); - method public java.util.List getMySessions(); - method public android.content.pm.InstallSessionInfo getSessionInfo(int); + method public int createSession(android.content.pm.PackageInstaller.SessionParams) throws java.io.IOException; + method public java.util.List getAllSessions(); + method public java.util.List getMySessions(); + method public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int); method public android.content.pm.PackageInstaller.Session openSession(int); method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback); - method public void uninstall(java.lang.String, android.content.pm.PackageInstaller.UninstallCallback); + method public void uninstall(java.lang.String, android.content.IntentSender); field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS"; + field public static final java.lang.String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES"; field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID"; - } - - public static abstract class PackageInstaller.CommitCallback { - ctor public PackageInstaller.CommitCallback(); - method public abstract void onFailure(int, java.lang.String, android.os.Bundle); - method public abstract void onSuccess(); - method public abstract void onUserActionRequired(android.content.Intent); - field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; - field public static final int FAILURE_ABORTED = 5; // 0x5 - field public static final int FAILURE_CONFLICT = 2; // 0x2 - field public static final int FAILURE_INCOMPATIBLE = 4; // 0x4 - field public static final int FAILURE_INVALID = 1; // 0x1 - field public static final int FAILURE_STORAGE = 3; // 0x3 - field public static final int FAILURE_UNKNOWN = 0; // 0x0 + field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS"; + field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE"; + field public static final int STATUS_FAILURE = 1; // 0x1 + field public static final int STATUS_FAILURE_ABORTED = 2; // 0x2 + field public static final int STATUS_FAILURE_BLOCKED = 1; // 0x1 + field public static final int STATUS_FAILURE_CONFLICT = 4; // 0x4 + field public static final int STATUS_FAILURE_INCOMPATIBLE = 6; // 0x6 + field public static final int STATUS_FAILURE_INVALID = 3; // 0x3 + field public static final int STATUS_FAILURE_STORAGE = 5; // 0x5 + field public static final int STATUS_SUCCESS = 0; // 0x0 + field public static final int STATUS_USER_ACTION_REQUIRED = -1; // 0xffffffff } public static class PackageInstaller.Session implements java.io.Closeable { method public void abandon(); method public void close(); - method public void commit(android.content.pm.PackageInstaller.CommitCallback); + method public void commit(android.content.IntentSender); method public void fsync(java.io.OutputStream) throws java.io.IOException; - method public java.lang.String[] list(); + method public java.lang.String[] getNames(); method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException; method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException; method public void setProgress(float); @@ -8720,14 +8688,34 @@ package android.content.pm { method public abstract void onProgressChanged(int, float); } - public static abstract class PackageInstaller.UninstallCallback { - ctor public PackageInstaller.UninstallCallback(); - method public abstract void onFailure(int, java.lang.String, android.os.Bundle); - method public abstract void onSuccess(); - method public abstract void onUserActionRequired(android.content.Intent); - field public static final int FAILURE_ABORTED = 2; // 0x2 - field public static final int FAILURE_BLOCKED = 1; // 0x1 - field public static final int FAILURE_UNKNOWN = 0; // 0x0 + public static class PackageInstaller.SessionInfo implements android.os.Parcelable { + method public int describeContents(); + method public android.graphics.Bitmap getAppIcon(); + method public java.lang.CharSequence getAppLabel(); + method public java.lang.String getAppPackageName(); + method public android.content.Intent getDetailsIntent(); + method public java.lang.String getInstallerPackageName(); + method public float getProgress(); + method public int getSessionId(); + method public boolean isOpen(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + + public static class PackageInstaller.SessionParams implements android.os.Parcelable { + ctor public PackageInstaller.SessionParams(int); + method public int describeContents(); + method public void setAppIcon(android.graphics.Bitmap); + method public void setAppLabel(java.lang.CharSequence); + method public void setAppPackageName(java.lang.String); + method public void setInstallLocation(int); + method public void setOriginatingUri(android.net.Uri); + method public void setReferrerUri(android.net.Uri); + method public void setSize(long); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + field public static final int MODE_FULL_INSTALL = 1; // 0x1 + field public static final int MODE_INHERIT_EXISTING = 2; // 0x2 } public class PackageItemInfo { diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 15152e522036e..46d8adeecd148 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -19,21 +19,22 @@ package com.android.commands.pm; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.IActivityManager; -import android.app.PackageDeleteObserver; import android.app.PackageInstallObserver; import android.content.ComponentName; +import android.content.IIntentReceiver; +import android.content.IIntentSender; import android.content.Intent; +import android.content.IntentSender; import android.content.pm.ApplicationInfo; import android.content.pm.FeatureInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageInstaller; import android.content.pm.IPackageManager; -import android.content.pm.InstallSessionInfo; -import android.content.pm.InstallSessionParams; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; -import android.content.pm.PackageInstaller.CommitCallback; +import android.content.pm.PackageInstaller.SessionInfo; +import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; @@ -74,6 +75,8 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.WeakHashMap; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.TimeUnit; public final class Pm { private static final String TAG = "Pm"; @@ -776,36 +779,6 @@ public final class Pm { } } - class LocalCommitCallback extends CommitCallback { - boolean finished; - boolean success; - String msg; - - private void setResult(boolean success, String msg) { - synchronized (this) { - this.finished = true; - this.success = success; - this.msg = msg; - notifyAll(); - } - } - - @Override - public void onUserActionRequired(Intent intent) { - setResult(false, "Unexepected user action required!"); - } - - @Override - public void onSuccess() { - setResult(true, null); - } - - @Override - public void onFailure(int failureReason, String msg, Bundle extras) { - setResult(false, msg); - } - } - /** * Converts a failure code into a string by using reflection to find a matching constant * in PackageManager. @@ -1007,8 +980,7 @@ public final class Pm { private void runInstallCreate() throws RemoteException { String installerPackageName = null; - final InstallSessionParams params = new InstallSessionParams( - InstallSessionParams.MODE_FULL_INSTALL); + final SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL); params.installFlags = PackageManager.INSTALL_ALL_USERS; String opt; @@ -1031,7 +1003,7 @@ public final class Pm { } else if (opt.equals("-d")) { params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; } else if (opt.equals("-p")) { - params.mode = InstallSessionParams.MODE_INHERIT_EXISTING; + params.mode = SessionParams.MODE_INHERIT_EXISTING; } else if (opt.equals("-S")) { params.setSize(Long.parseLong(nextOptionData())); } else if (opt.equals("--abi")) { @@ -1073,7 +1045,7 @@ public final class Pm { } } - final InstallSessionInfo info = mInstaller.getSessionInfo(sessionId); + final SessionInfo info = mInstaller.getSessionInfo(sessionId); PackageInstaller.Session session = null; InputStream in = null; @@ -1117,22 +1089,20 @@ public final class Pm { try { session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); - final LocalCommitCallback callback = new LocalCommitCallback(); - session.commit(callback); + final LocalIntentReceiver receiver = new LocalIntentReceiver(); + session.commit(receiver.getIntentSender()); - synchronized (callback) { - while (!callback.finished) { - try { - callback.wait(); - } catch (InterruptedException e) { - } - } - if (!callback.success) { - throw new IllegalStateException("Failure [" + callback.msg + "]"); - } + final Intent result = receiver.getResult(); + final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_FAILURE); + if (status == PackageInstaller.STATUS_SUCCESS) { + System.out.println("Success"); + } else { + Log.e(TAG, "Failure details: " + result.getExtras()); + System.out.println("Failure [" + + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); + return; } - - System.out.println("Success"); } finally { IoUtils.closeQuietly(session); } @@ -1274,28 +1244,14 @@ public final class Pm { } } - class LocalPackageDeleteObserver extends PackageDeleteObserver { - boolean finished; - boolean result; - - @Override - public void onPackageDeleted(String name, int returnCode, String msg) { - synchronized (this) { - finished = true; - result = returnCode == PackageManager.DELETE_SUCCEEDED; - notifyAll(); - } - } - } - - private void runUninstall() { - int unInstallFlags = 0; + private void runUninstall() throws RemoteException { + int flags = 0; int userId = UserHandle.USER_ALL; String opt; while ((opt=nextOption()) != null) { if (opt.equals("-k")) { - unInstallFlags |= PackageManager.DELETE_KEEP_DATA; + flags |= PackageManager.DELETE_KEEP_DATA; } else if (opt.equals("--user")) { String param = nextArg(); if (isNumber(param)) { @@ -1320,7 +1276,7 @@ public final class Pm { if (userId == UserHandle.USER_ALL) { userId = UserHandle.USER_OWNER; - unInstallFlags |= PackageManager.DELETE_ALL_USERS; + flags |= PackageManager.DELETE_ALL_USERS; } else { PackageInfo info; try { @@ -1340,38 +1296,25 @@ public final class Pm { // user set flag so it disables rather than reverting to system // version of the app. if (isSystem) { - unInstallFlags |= PackageManager.DELETE_SYSTEM_APP; + flags |= PackageManager.DELETE_SYSTEM_APP; } } - boolean result = deletePackage(pkg, unInstallFlags, userId); - if (result) { + final LocalIntentReceiver receiver = new LocalIntentReceiver(); + mInstaller.uninstall(pkg, flags, receiver.getIntentSender(), userId); + + final Intent result = receiver.getResult(); + final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_FAILURE); + if (status == PackageInstaller.STATUS_SUCCESS) { System.out.println("Success"); } else { - System.out.println("Failure"); + Log.e(TAG, "Failure details: " + result.getExtras()); + System.out.println("Failure [" + + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); } } - private boolean deletePackage(String packageName, int flags, int userId) { - LocalPackageDeleteObserver obs = new LocalPackageDeleteObserver(); - try { - mInstaller.uninstall(packageName, flags, obs.getBinder(), userId); - - synchronized (obs) { - while (!obs.finished) { - try { - obs.wait(); - } catch (InterruptedException e) { - } - } - } - } catch (RemoteException e) { - System.err.println(e.toString()); - System.err.println(PM_NOT_RUNNING_ERR); - } - return obs.result; - } - static class ClearDataObserver extends IPackageDataObserver.Stub { boolean finished; boolean result; @@ -1384,7 +1327,6 @@ public final class Pm { notifyAll(); } } - } private void runClear() { @@ -1717,6 +1659,35 @@ public final class Pm { throw new IllegalArgumentException("ABI " + abi + " not supported on this device"); } + private static class LocalIntentReceiver { + private final SynchronousQueue mResult = new SynchronousQueue<>(); + + private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { + @Override + public int send(int code, Intent intent, String resolvedType, + IIntentReceiver finishedReceiver, String requiredPermission) { + try { + mResult.offer(intent, 5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return 0; + } + }; + + public IntentSender getIntentSender() { + return new IntentSender((IIntentSender) mLocalSender); + } + + public Intent getResult() { + try { + return mResult.poll(30, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + private String nextOption() { if (mNextArg >= mArgs.length) { return null; diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index a935dc02c3fc1..b2812e3099ca8 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1568,7 +1568,7 @@ final class ApplicationPackageManager extends PackageManager { synchronized (mLock) { if (mInstaller == null) { try { - mInstaller = new PackageInstaller(this, mPM.getPackageInstaller(), + mInstaller = new PackageInstaller(mContext, this, mPM.getPackageInstaller(), mContext.getPackageName(), mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 5223476fc43d2..97be8f0e080b0 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -19,23 +19,22 @@ package android.content.pm; import android.content.pm.IPackageDeleteObserver2; import android.content.pm.IPackageInstallerCallback; import android.content.pm.IPackageInstallerSession; -import android.content.pm.InstallSessionInfo; -import android.content.pm.InstallSessionParams; +import android.content.pm.PackageInstaller; +import android.content.IntentSender; /** {@hide} */ interface IPackageInstaller { - int createSession(in InstallSessionParams params, String installerPackageName, int userId); + int createSession(in PackageInstaller.SessionParams params, String installerPackageName, int userId); IPackageInstallerSession openSession(int sessionId); - InstallSessionInfo getSessionInfo(int sessionId); - List getAllSessions(int userId); - List getMySessions(String installerPackageName, int userId); + PackageInstaller.SessionInfo getSessionInfo(int sessionId); + List getAllSessions(int userId); + List getMySessions(String installerPackageName, int userId); void registerCallback(IPackageInstallerCallback callback, int userId); void unregisterCallback(IPackageInstallerCallback callback); - void uninstall(String packageName, int flags, in IPackageDeleteObserver2 observer, int userId); - void uninstallSplit(String packageName, String splitName, int flags, in IPackageDeleteObserver2 observer, int userId); + void uninstall(String packageName, int flags, in IntentSender statusReceiver, int userId); void setPermissionsResult(int sessionId, boolean accepted); } diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index af0323fe30599..aee3ba77f1f08 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -17,6 +17,7 @@ package android.content.pm; import android.content.pm.IPackageInstallObserver2; +import android.content.IntentSender; import android.os.ParcelFileDescriptor; /** {@hide} */ @@ -24,11 +25,11 @@ interface IPackageInstallerSession { void setClientProgress(float progress); void addClientProgress(float progress); - String[] list(); + String[] getNames(); ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes); ParcelFileDescriptor openRead(String name); void close(); - void commit(in IPackageInstallObserver2 observer); + void commit(in IntentSender statusReceiver); void abandon(); } diff --git a/core/java/android/content/pm/InstallSessionInfo.java b/core/java/android/content/pm/InstallSessionInfo.java deleted file mode 100644 index 161bcde5a666c..0000000000000 --- a/core/java/android/content/pm/InstallSessionInfo.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2014 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; - -import android.annotation.Nullable; -import android.content.Intent; -import android.graphics.Bitmap; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Details for an active install session. - */ -public class InstallSessionInfo implements Parcelable { - - /** {@hide} */ - public int sessionId; - /** {@hide} */ - public String installerPackageName; - /** {@hide} */ - public String resolvedBaseCodePath; - /** {@hide} */ - public float progress; - /** {@hide} */ - public boolean sealed; - /** {@hide} */ - public boolean open; - - /** {@hide} */ - public int mode; - /** {@hide} */ - public long sizeBytes; - /** {@hide} */ - public String appPackageName; - /** {@hide} */ - public Bitmap appIcon; - /** {@hide} */ - public CharSequence appLabel; - - /** {@hide} */ - public InstallSessionInfo() { - } - - /** {@hide} */ - public InstallSessionInfo(Parcel source) { - sessionId = source.readInt(); - installerPackageName = source.readString(); - resolvedBaseCodePath = source.readString(); - progress = source.readFloat(); - sealed = source.readInt() != 0; - open = source.readInt() != 0; - - mode = source.readInt(); - sizeBytes = source.readLong(); - appPackageName = source.readString(); - appIcon = source.readParcelable(null); - appLabel = source.readString(); - } - - /** - * Return the ID for this session. - */ - public int getSessionId() { - return sessionId; - } - - /** - * Return the package name of the app that owns this session. - */ - public @Nullable String getInstallerPackageName() { - return installerPackageName; - } - - /** - * Return current overall progress of this session, between 0 and 1. - *

- * Note that this progress may not directly correspond to the value reported - * by {@link PackageInstaller.Session#setProgress(float)}, as the system may - * carve out a portion of the overall progress to represent its own internal - * installation work. - */ - public float getProgress() { - return progress; - } - - /** - * Return if this session is currently open. - */ - public boolean isOpen() { - return open; - } - - /** - * Return the package name this session is working with. May be {@code null} - * if unknown. - */ - public @Nullable String getAppPackageName() { - return appPackageName; - } - - /** - * Return an icon representing the app being installed. May be {@code null} - * if unavailable. - */ - public @Nullable Bitmap getAppIcon() { - return appIcon; - } - - /** - * Return a label representing the app being installed. May be {@code null} - * if unavailable. - */ - public @Nullable CharSequence getAppLabel() { - return appLabel; - } - - /** - * Return an Intent that can be started to view details about this install - * session. This may surface actions such as pause, resume, or cancel. - *

- * In some cases, a matching Activity may not exist, so ensure you safeguard - * against this. - * - * @see PackageInstaller#ACTION_SESSION_DETAILS - */ - public @Nullable Intent getDetailsIntent() { - final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS); - intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); - intent.setPackage(installerPackageName); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - return intent; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(sessionId); - dest.writeString(installerPackageName); - dest.writeString(resolvedBaseCodePath); - dest.writeFloat(progress); - dest.writeInt(sealed ? 1 : 0); - dest.writeInt(open ? 1 : 0); - - dest.writeInt(mode); - dest.writeLong(sizeBytes); - dest.writeString(appPackageName); - dest.writeParcelable(appIcon, flags); - dest.writeString(appLabel != null ? appLabel.toString() : null); - } - - public static final Parcelable.Creator - CREATOR = new Parcelable.Creator() { - @Override - public InstallSessionInfo createFromParcel(Parcel p) { - return new InstallSessionInfo(p); - } - - @Override - public InstallSessionInfo[] newArray(int size) { - return new InstallSessionInfo[size]; - } - }; -} diff --git a/core/java/android/content/pm/InstallSessionParams.aidl b/core/java/android/content/pm/InstallSessionParams.aidl deleted file mode 100644 index 81b75740301d3..0000000000000 --- a/core/java/android/content/pm/InstallSessionParams.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2014 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; - -parcelable InstallSessionParams; diff --git a/core/java/android/content/pm/InstallSessionParams.java b/core/java/android/content/pm/InstallSessionParams.java deleted file mode 100644 index 1716e397cf3e2..0000000000000 --- a/core/java/android/content/pm/InstallSessionParams.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2014 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; - -import android.annotation.Nullable; -import android.app.ActivityManager; -import android.content.Intent; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.util.IndentingPrintWriter; - -/** - * Parameters for creating a new {@link PackageInstaller.Session}. - */ -public class InstallSessionParams implements Parcelable { - - /** {@hide} */ - public static final int MODE_INVALID = -1; - - /** - * Mode for an install session whose staged APKs should fully replace any - * existing APKs for the target app. - */ - public static final int MODE_FULL_INSTALL = 1; - - /** - * Mode for an install session that should inherit any existing APKs for the - * target app, unless they have been explicitly overridden (based on split - * name) by the session. For example, this can be used to add one or more - * split APKs to an existing installation. - *

- * If there are no existing APKs for the target app, this behaves like - * {@link #MODE_FULL_INSTALL}. - */ - public static final int MODE_INHERIT_EXISTING = 2; - - /** {@hide} */ - public int mode = MODE_INVALID; - /** {@hide} */ - public int installFlags; - /** {@hide} */ - public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; - /** {@hide} */ - public long sizeBytes = -1; - /** {@hide} */ - public String appPackageName; - /** {@hide} */ - public Bitmap appIcon; - /** {@hide} */ - public String appLabel; - /** {@hide} */ - public Uri originatingUri; - /** {@hide} */ - public Uri referrerUri; - /** {@hide} */ - public String abiOverride; - - /** - * Construct parameters for a new package install session. - * - * @param mode one of {@link #MODE_FULL_INSTALL} or - * {@link #MODE_INHERIT_EXISTING} describing how the session - * should interact with an existing app. - */ - public InstallSessionParams(int mode) { - this.mode = mode; - } - - /** {@hide} */ - public InstallSessionParams(Parcel source) { - mode = source.readInt(); - installFlags = source.readInt(); - installLocation = source.readInt(); - sizeBytes = source.readLong(); - appPackageName = source.readString(); - appIcon = source.readParcelable(null); - appLabel = source.readString(); - originatingUri = source.readParcelable(null); - referrerUri = source.readParcelable(null); - abiOverride = source.readString(); - } - - /** - * Provide value of {@link PackageInfo#installLocation}, which may be used - * to determine where the app will be staged. Defaults to - * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}. - */ - public void setInstallLocation(int installLocation) { - this.installLocation = installLocation; - } - - /** - * @deprecated use {@link PackageInstaller.Session#openRead(String)} to - * calculate message digest instead. - * @hide - */ - @Deprecated - public void setSignatures(@Nullable Signature[] signatures) { - throw new UnsupportedOperationException(); - } - - /** - * Optionally indicate the total size (in bytes) of all APKs that will be - * delivered in this session. The system may use this to ensure enough disk - * space exists before proceeding, or to estimate container size for - * installations living on external storage. - * - * @see PackageInfo#INSTALL_LOCATION_AUTO - * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL - */ - public void setSize(long sizeBytes) { - this.sizeBytes = sizeBytes; - } - - /** - * Optionally set the package name of the app being installed. It's strongly - * recommended that you provide this value when known, so that observers can - * communicate installing apps to users. - *

- * If the APKs staged in the session aren't consistent with this package - * name, the install will fail. Regardless of this value, all APKs in the - * app must have the same package name. - */ - public void setAppPackageName(@Nullable String appPackageName) { - this.appPackageName = appPackageName; - } - - /** - * Optionally set an icon representing the app being installed. This should - * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both - * dimensions. - */ - public void setAppIcon(@Nullable Bitmap appIcon) { - this.appIcon = appIcon; - } - - /** - * Optionally set a label representing the app being installed. - */ - public void setAppLabel(@Nullable CharSequence appLabel) { - this.appLabel = (appLabel != null) ? appLabel.toString() : null; - } - - /** - * Optionally set the URI where this package was downloaded from. Used for - * verification purposes. - * - * @see Intent#EXTRA_ORIGINATING_URI - */ - public void setOriginatingUri(@Nullable Uri originatingUri) { - this.originatingUri = originatingUri; - } - - /** - * Optionally set the URI that referred you to install this package. Used - * for verification purposes. - * - * @see Intent#EXTRA_REFERRER - */ - public void setReferrerUri(@Nullable Uri referrerUri) { - this.referrerUri = referrerUri; - } - - /** {@hide} */ - public void dump(IndentingPrintWriter pw) { - pw.printPair("mode", mode); - pw.printHexPair("installFlags", installFlags); - pw.printPair("installLocation", installLocation); - pw.printPair("sizeBytes", sizeBytes); - pw.printPair("appPackageName", appPackageName); - pw.printPair("appIcon", (appIcon != null)); - pw.printPair("appLabel", appLabel); - pw.printPair("originatingUri", originatingUri); - pw.printPair("referrerUri", referrerUri); - pw.printPair("abiOverride", abiOverride); - pw.println(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mode); - dest.writeInt(installFlags); - dest.writeInt(installLocation); - dest.writeLong(sizeBytes); - dest.writeString(appPackageName); - dest.writeParcelable(appIcon, flags); - dest.writeString(appLabel); - dest.writeParcelable(originatingUri, flags); - dest.writeParcelable(referrerUri, flags); - dest.writeString(abiOverride); - } - - public static final Parcelable.Creator - CREATOR = new Parcelable.Creator() { - @Override - public InstallSessionParams createFromParcel(Parcel p) { - return new InstallSessionParams(p); - } - - @Override - public InstallSessionParams[] newArray(int size) { - return new InstallSessionParams[size]; - } - }; -} diff --git a/core/java/android/content/pm/InstallSessionInfo.aidl b/core/java/android/content/pm/PackageInstaller.aidl similarity index 88% rename from core/java/android/content/pm/InstallSessionInfo.aidl rename to core/java/android/content/pm/PackageInstaller.aidl index 3d21bbdf82498..270f870405f51 100644 --- a/core/java/android/content/pm/InstallSessionInfo.aidl +++ b/core/java/android/content/pm/PackageInstaller.aidl @@ -16,4 +16,5 @@ package android.content.pm; -parcelable InstallSessionInfo; +parcelable PackageInstaller.SessionParams; +parcelable PackageInstaller.SessionInfo; diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index d70e22caa64d0..aa4ea454fc5cf 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -20,17 +20,24 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.app.PackageDeleteObserver; -import android.app.PackageInstallObserver; +import android.app.ActivityManager; +import android.content.Context; import android.content.Intent; -import android.os.Bundle; +import android.content.IntentSender; +import android.graphics.Bitmap; +import android.net.Uri; import android.os.FileBridge; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.Parcel; import android.os.ParcelFileDescriptor; +import android.os.Parcelable; import android.os.RemoteException; import android.util.ExceptionUtils; +import android.util.Log; + +import com.android.internal.util.IndentingPrintWriter; import java.io.Closeable; import java.io.IOException; @@ -67,13 +74,15 @@ import java.util.List; * */ public class PackageInstaller { + private static final String TAG = "PackageInstaller"; + /** * Activity Action: Show details about a particular install session. This * may surface actions such as pause, resume, or cancel. *

* This should always be scoped to the installer package that owns the - * session. Clients should use {@link InstallSessionInfo#getDetailsIntent()} - * to build this intent correctly. + * session. Clients should use {@link SessionInfo#getDetailsIntent()} to + * build this intent correctly. *

* In some cases, a matching Activity may not exist, so ensure you safeguard * against this. @@ -92,9 +101,110 @@ public class PackageInstaller { */ public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID"; + public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS"; + public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE"; + + /** + * List of package names that are relevant to a status. + * + * @see Intent#getStringArrayExtra(String) + */ + public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES"; + + /** {@hide} */ + public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS"; + /** {@hide} */ + public static final String EXTRA_LEGACY_BUNDLE = "android.content.pm.extra.LEGACY_BUNDLE"; /** {@hide} */ public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK"; + /** + * User action is currently required to proceed. You can launch the intent + * activity described by {@link Intent#EXTRA_INTENT} to involve the user and + * continue. + *

+ * You may choose to immediately launch the intent if the user is actively + * using your app. Otherwise, you should use a notification to guide the + * user back into your app before launching. + * + * @see Intent#getParcelableExtra(String) + */ + public static final int STATUS_USER_ACTION_REQUIRED = -1; + + /** + * The operation succeeded. + */ + public static final int STATUS_SUCCESS = 0; + + /** + * The operation failed in a generic way. The system will always try to + * provide a more specific failure reason, but in some rare cases this may + * be delivered. + * + * @see #EXTRA_STATUS_MESSAGE + */ + public static final int STATUS_FAILURE = 1; + + /** + * The operation failed because it was blocked. For example, a device policy + * may be blocking the operation, a package verifier may have blocked the + * operation, or the app may be required for core system operation. + * + * @see #EXTRA_STATUS_MESSAGE + */ + public static final int STATUS_FAILURE_BLOCKED = 1; + + /** + * The operation failed because it was actively aborted. For example, the + * user actively declined requested permissions, or the session was + * abandoned. + * + * @see #EXTRA_STATUS_MESSAGE + */ + public static final int STATUS_FAILURE_ABORTED = 2; + + /** + * The operation failed because one or more of the APKs was invalid. For + * example, they might be malformed, corrupt, incorrectly signed, + * mismatched, etc. + * + * @see #EXTRA_STATUS_MESSAGE + */ + public static final int STATUS_FAILURE_INVALID = 3; + + /** + * The operation failed because it conflicts (or is inconsistent with) with + * another package already installed on the device. For example, an existing + * permission, incompatible certificates, etc. The user may be able to + * uninstall another app to fix the issue. + *

+ * The result may also contain {@link #EXTRA_PACKAGE_NAMES} with the + * specific packages identified as the cause of the conflict. + * + * @see #EXTRA_STATUS_MESSAGE + */ + public static final int STATUS_FAILURE_CONFLICT = 4; + + /** + * The operation failed because of storage issues. For example, the device + * may be running low on space, or external media may be unavailable. The + * user may be able to help free space or insert different external media. + * + * @see #EXTRA_STATUS_MESSAGE + */ + public static final int STATUS_FAILURE_STORAGE = 5; + + /** + * The operation failed because it is fundamentally incompatible with this + * device. For example, the app may require a hardware feature that doesn't + * exist, it may be missing native code for the ABIs supported by the + * device, or it requires a newer SDK version, etc. + * + * @see #EXTRA_STATUS_MESSAGE + */ + public static final int STATUS_FAILURE_INCOMPATIBLE = 6; + + private final Context mContext; private final PackageManager mPm; private final IPackageInstaller mInstaller; private final int mUserId; @@ -103,8 +213,9 @@ public class PackageInstaller { private final ArrayList mDelegates = new ArrayList<>(); /** {@hide} */ - public PackageInstaller(PackageManager pm, IPackageInstaller installer, + public PackageInstaller(Context context, PackageManager pm, IPackageInstaller installer, String installerPackageName, int userId) { + mContext = context; mPm = pm; mInstaller = installer; mInstallerPackageName = installerPackageName; @@ -126,7 +237,7 @@ public class PackageInstaller { * This ID remains consistent across device reboots until the * session is finalized. IDs are not reused during a given boot. */ - public int createSession(@NonNull InstallSessionParams params) throws IOException { + public int createSession(@NonNull SessionParams params) throws IOException { try { return mInstaller.createSession(params, mInstallerPackageName, mUserId); } catch (RuntimeException e) { @@ -153,7 +264,7 @@ public class PackageInstaller { * Return details for a specific session. To succeed, the caller must either * own this session, or be the current home app. */ - public @Nullable InstallSessionInfo getSessionInfo(int sessionId) { + public @Nullable SessionInfo getSessionInfo(int sessionId) { try { return mInstaller.getSessionInfo(sessionId); } catch (RemoteException e) { @@ -165,7 +276,7 @@ public class PackageInstaller { * Return list of all active install sessions, regardless of the installer. * To succeed, the caller must be the current home app. */ - public @NonNull List getAllSessions() { + public @NonNull List getAllSessions() { try { return mInstaller.getAllSessions(mUserId); } catch (RemoteException e) { @@ -176,7 +287,7 @@ public class PackageInstaller { /** * Return list of all install sessions owned by the calling app. */ - public @NonNull List getMySessions() { + public @NonNull List getMySessions() { try { return mInstaller.getMySessions(mInstallerPackageName, mUserId); } catch (RemoteException e) { @@ -189,25 +300,9 @@ public class PackageInstaller { * method is only available to the current "installer of record" for the * package. */ - public void uninstall(@NonNull String packageName, @NonNull UninstallCallback callback) { + public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) { try { - mInstaller.uninstall(packageName, 0, - new UninstallCallbackDelegate(callback).getBinder(), mUserId); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } - - /** - * Uninstall only a specific split from the given package. - * - * @hide - */ - public void uninstall(@NonNull String packageName, @NonNull String splitName, - @NonNull UninstallCallback callback) { - try { - mInstaller.uninstallSplit(packageName, splitName, 0, - new UninstallCallbackDelegate(callback).getBinder(), mUserId); + mInstaller.uninstall(packageName, 0, statusReceiver, mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -353,6 +448,14 @@ public class PackageInstaller { * calling thread. */ public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { + // TODO: remove this temporary guard once we have new prebuilts + final ApplicationInfo info = mContext.getApplicationInfo(); + if ("com.google.android.googlequicksearchbox".equals(info.packageName) + && info.versionCode <= 300400070) { + Log.d(TAG, "Ignoring callback request from old prebuilt"); + return; + } + synchronized (mDelegates) { final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback, handler.getLooper()); @@ -436,7 +539,7 @@ public class PackageInstaller { * You can write data into the returned stream, optionally call * {@link #fsync(OutputStream)} as needed to ensure bytes have been * persisted to disk, and then close when finished. All streams must be - * closed before calling {@link #commit(CommitCallback)}. + * closed before calling {@link #commit(IntentSender)}. * * @param name arbitrary, unique name of your choosing to identify the * APK being written. You can open a file again for @@ -476,14 +579,14 @@ public class PackageInstaller { } /** - * List all APK names contained in this session. + * Return all APK names contained in this session. *

* This returns all names which have been previously written through * {@link #openWrite(String, long, long)} as part of this session. */ - public @NonNull String[] list() { + public @NonNull String[] getNames() { try { - return mSession.list(); + return mSession.getNames(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -518,9 +621,9 @@ public class PackageInstaller { * on the session. If the device reboots before the session has been * finalized, you may commit the session again. */ - public void commit(@NonNull CommitCallback callback) { + public void commit(@NonNull IntentSender statusReceiver) { try { - mSession.commit(new CommitCallbackDelegate(callback).getBinder()); + mSession.commit(statusReceiver); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -553,169 +656,350 @@ public class PackageInstaller { } /** - * Events for a specific uninstall request. + * Parameters for creating a new {@link PackageInstaller.Session}. */ - public static abstract class UninstallCallback { - /** - * Generic unknown failure. The system will always try to provide a more - * specific failure reason, but in some rare cases this may be - * delivered. - */ - public static final int FAILURE_UNKNOWN = 0; + public static class SessionParams implements Parcelable { + + /** {@hide} */ + public static final int MODE_INVALID = -1; /** - * This uninstall was blocked. The package may be required for core - * system operation, or the user may be restricted. Attempting to - * uninstall again will have the same result. + * Mode for an install session whose staged APKs should fully replace any + * existing APKs for the target app. */ - public static final int FAILURE_BLOCKED = 1; + public static final int MODE_FULL_INSTALL = 1; /** - * This uninstall was actively aborted. For example, the user declined - * to uninstall. You may try to uninstall again. - */ - public static final int FAILURE_ABORTED = 2; - - /** - * User action is required to proceed. You can start the given intent - * activity to involve the user and continue. + * Mode for an install session that should inherit any existing APKs for the + * target app, unless they have been explicitly overridden (based on split + * name) by the session. For example, this can be used to add one or more + * split APKs to an existing installation. *

- * You may choose to immediately launch the intent if the user is - * actively using your app. However, you should use a notification to - * guide the user back into your app if not currently active. + * If there are no existing APKs for the target app, this behaves like + * {@link #MODE_FULL_INSTALL}. */ - public abstract void onUserActionRequired(Intent intent); + public static final int MODE_INHERIT_EXISTING = 2; - public abstract void onSuccess(); - public abstract void onFailure(int failureReason, String msg, Bundle extras); - } + /** {@hide} */ + public int mode = MODE_INVALID; + /** {@hide} */ + public int installFlags; + /** {@hide} */ + public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; + /** {@hide} */ + public long sizeBytes = -1; + /** {@hide} */ + public String appPackageName; + /** {@hide} */ + public Bitmap appIcon; + /** {@hide} */ + public String appLabel; + /** {@hide} */ + public Uri originatingUri; + /** {@hide} */ + public Uri referrerUri; + /** {@hide} */ + public String abiOverride; - /** {@hide} */ - private static class UninstallCallbackDelegate extends PackageDeleteObserver { - private final UninstallCallback target; + /** + * Construct parameters for a new package install session. + * + * @param mode one of {@link #MODE_FULL_INSTALL} or + * {@link #MODE_INHERIT_EXISTING} describing how the session + * should interact with an existing app. + */ + public SessionParams(int mode) { + this.mode = mode; + } - public UninstallCallbackDelegate(UninstallCallback target) { - this.target = target; + /** {@hide} */ + public SessionParams(Parcel source) { + mode = source.readInt(); + installFlags = source.readInt(); + installLocation = source.readInt(); + sizeBytes = source.readLong(); + appPackageName = source.readString(); + appIcon = source.readParcelable(null); + appLabel = source.readString(); + originatingUri = source.readParcelable(null); + referrerUri = source.readParcelable(null); + abiOverride = source.readString(); + } + + /** + * Provide value of {@link PackageInfo#installLocation}, which may be used + * to determine where the app will be staged. Defaults to + * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}. + */ + public void setInstallLocation(int installLocation) { + this.installLocation = installLocation; + } + + /** + * Optionally indicate the total size (in bytes) of all APKs that will be + * delivered in this session. The system may use this to ensure enough disk + * space exists before proceeding, or to estimate container size for + * installations living on external storage. + * + * @see PackageInfo#INSTALL_LOCATION_AUTO + * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL + */ + public void setSize(long sizeBytes) { + this.sizeBytes = sizeBytes; + } + + /** + * Optionally set the package name of the app being installed. It's strongly + * recommended that you provide this value when known, so that observers can + * communicate installing apps to users. + *

+ * If the APKs staged in the session aren't consistent with this package + * name, the install will fail. Regardless of this value, all APKs in the + * app must have the same package name. + */ + public void setAppPackageName(@Nullable String appPackageName) { + this.appPackageName = appPackageName; + } + + /** + * Optionally set an icon representing the app being installed. This should + * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both + * dimensions. + */ + public void setAppIcon(@Nullable Bitmap appIcon) { + this.appIcon = appIcon; + } + + /** + * Optionally set a label representing the app being installed. + */ + public void setAppLabel(@Nullable CharSequence appLabel) { + this.appLabel = (appLabel != null) ? appLabel.toString() : null; + } + + /** + * Optionally set the URI where this package was downloaded from. Used for + * verification purposes. + * + * @see Intent#EXTRA_ORIGINATING_URI + */ + public void setOriginatingUri(@Nullable Uri originatingUri) { + this.originatingUri = originatingUri; + } + + /** + * Optionally set the URI that referred you to install this package. Used + * for verification purposes. + * + * @see Intent#EXTRA_REFERRER + */ + public void setReferrerUri(@Nullable Uri referrerUri) { + this.referrerUri = referrerUri; + } + + /** {@hide} */ + public void dump(IndentingPrintWriter pw) { + pw.printPair("mode", mode); + pw.printHexPair("installFlags", installFlags); + pw.printPair("installLocation", installLocation); + pw.printPair("sizeBytes", sizeBytes); + pw.printPair("appPackageName", appPackageName); + pw.printPair("appIcon", (appIcon != null)); + pw.printPair("appLabel", appLabel); + pw.printPair("originatingUri", originatingUri); + pw.printPair("referrerUri", referrerUri); + pw.printPair("abiOverride", abiOverride); + pw.println(); } @Override - public void onUserActionRequired(Intent intent) { - target.onUserActionRequired(intent); + public int describeContents() { + return 0; } @Override - public void onPackageDeleted(String basePackageName, int returnCode, String msg) { - if (returnCode == PackageManager.DELETE_SUCCEEDED) { - target.onSuccess(); - } else { - final int failureReason = PackageManager.deleteStatusToFailureReason(returnCode); - msg = PackageManager.deleteStatusToString(returnCode) + ": " + msg; - target.onFailure(failureReason, msg, null); - } + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mode); + dest.writeInt(installFlags); + dest.writeInt(installLocation); + dest.writeLong(sizeBytes); + dest.writeString(appPackageName); + dest.writeParcelable(appIcon, flags); + dest.writeString(appLabel); + dest.writeParcelable(originatingUri, flags); + dest.writeParcelable(referrerUri, flags); + dest.writeString(abiOverride); } + + public static final Parcelable.Creator + CREATOR = new Parcelable.Creator() { + @Override + public SessionParams createFromParcel(Parcel p) { + return new SessionParams(p); + } + + @Override + public SessionParams[] newArray(int size) { + return new SessionParams[size]; + } + }; } /** - * Final result of a session commit request. + * Details for an active install session. */ - public static abstract class CommitCallback { - /** - * Generic unknown failure. The system will always try to provide a more - * specific failure reason, but in some rare cases this may be - * delivered. - */ - public static final int FAILURE_UNKNOWN = 0; + public static class SessionInfo implements Parcelable { + + /** {@hide} */ + public int sessionId; + /** {@hide} */ + public String installerPackageName; + /** {@hide} */ + public String resolvedBaseCodePath; + /** {@hide} */ + public float progress; + /** {@hide} */ + public boolean sealed; + /** {@hide} */ + public boolean open; + + /** {@hide} */ + public int mode; + /** {@hide} */ + public long sizeBytes; + /** {@hide} */ + public String appPackageName; + /** {@hide} */ + public Bitmap appIcon; + /** {@hide} */ + public CharSequence appLabel; + + /** {@hide} */ + public SessionInfo() { + } + + /** {@hide} */ + public SessionInfo(Parcel source) { + sessionId = source.readInt(); + installerPackageName = source.readString(); + resolvedBaseCodePath = source.readString(); + progress = source.readFloat(); + sealed = source.readInt() != 0; + open = source.readInt() != 0; + + mode = source.readInt(); + sizeBytes = source.readLong(); + appPackageName = source.readString(); + appIcon = source.readParcelable(null); + appLabel = source.readString(); + } /** - * One or more of the APKs included in the session was invalid. For - * example, they might be malformed, corrupt, incorrectly signed, - * mismatched, etc. The installer may want to try downloading and - * installing again. + * Return the ID for this session. */ - public static final int FAILURE_INVALID = 1; + public int getSessionId() { + return sessionId; + } /** - * This install session conflicts (or is inconsistent with) with another - * package already installed on the device. For example, an existing - * permission, incompatible certificates, etc. The user may be able to - * uninstall another app to fix the issue. + * Return the package name of the app that owns this session. + */ + public @Nullable String getInstallerPackageName() { + return installerPackageName; + } + + /** + * Return current overall progress of this session, between 0 and 1. *

- * The extras bundle may contain {@link #EXTRA_PACKAGE_NAME} with the - * specific packages identified as the cause of the conflict. + * Note that this progress may not directly correspond to the value reported + * by {@link PackageInstaller.Session#setProgress(float)}, as the system may + * carve out a portion of the overall progress to represent its own internal + * installation work. */ - public static final int FAILURE_CONFLICT = 2; + public float getProgress() { + return progress; + } /** - * This install session failed due to storage issues. For example, - * the device may be running low on space, or the required external - * media may be unavailable. The user may be able to help free space - * or insert the correct media. + * Return if this session is currently open. */ - public static final int FAILURE_STORAGE = 3; + public boolean isOpen() { + return open; + } /** - * This install session is fundamentally incompatible with this - * device. For example, the package may require a hardware feature - * that doesn't exist, it may be missing native code for the device - * ABI, or it requires a newer SDK version, etc. This install would - * never succeed. + * Return the package name this session is working with. May be {@code null} + * if unknown. */ - public static final int FAILURE_INCOMPATIBLE = 4; + public @Nullable String getAppPackageName() { + return appPackageName; + } /** - * This install session failed because it was actively aborted. For - * example, the user declined requested permissions, or a verifier - * rejected the session. + * Return an icon representing the app being installed. May be {@code null} + * if unavailable. + */ + public @Nullable Bitmap getAppIcon() { + return appIcon; + } + + /** + * Return a label representing the app being installed. May be {@code null} + * if unavailable. + */ + public @Nullable CharSequence getAppLabel() { + return appLabel; + } + + /** + * Return an Intent that can be started to view details about this install + * session. This may surface actions such as pause, resume, or cancel. + *

+ * In some cases, a matching Activity may not exist, so ensure you safeguard + * against this. * - * @see PackageManager#VERIFICATION_REJECT + * @see PackageInstaller#ACTION_SESSION_DETAILS */ - public static final int FAILURE_ABORTED = 5; - - public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; - - /** - * User action is required to proceed. You can start the given intent - * activity to involve the user and continue. - *

- * You may choose to immediately launch the intent if the user is - * actively using your app. However, you should use a notification to - * guide the user back into your app if not currently active. - */ - public abstract void onUserActionRequired(Intent intent); - - public abstract void onSuccess(); - public abstract void onFailure(int failureReason, String msg, Bundle extras); - } - - /** {@hide} */ - private static class CommitCallbackDelegate extends PackageInstallObserver { - private final CommitCallback target; - - public CommitCallbackDelegate(CommitCallback target) { - this.target = target; + public @Nullable Intent getDetailsIntent() { + final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS); + intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); + intent.setPackage(installerPackageName); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return intent; } @Override - public void onUserActionRequired(Intent intent) { - target.onUserActionRequired(intent); + public int describeContents() { + return 0; } @Override - public void onPackageInstalled(String basePackageName, int returnCode, String msg, - Bundle extras) { - if (returnCode == PackageManager.INSTALL_SUCCEEDED) { - target.onSuccess(); - } else { - final int failureReason = PackageManager.installStatusToFailureReason(returnCode); - msg = PackageManager.installStatusToString(returnCode) + ": " + msg; + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(sessionId); + dest.writeString(installerPackageName); + dest.writeString(resolvedBaseCodePath); + dest.writeFloat(progress); + dest.writeInt(sealed ? 1 : 0); + dest.writeInt(open ? 1 : 0); - if (extras != null) { - extras.putString(CommitCallback.EXTRA_PACKAGE_NAME, - extras.getString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE)); - } - - target.onFailure(failureReason, msg, extras); - } + dest.writeInt(mode); + dest.writeLong(sizeBytes); + dest.writeString(appPackageName); + dest.writeParcelable(appIcon, flags); + dest.writeString(appLabel != null ? appLabel.toString() : null); } + + public static final Parcelable.Creator + CREATOR = new Parcelable.Creator() { + @Override + public SessionInfo createFromParcel(Parcel p) { + return new SessionInfo(p); + } + + @Override + public SessionInfo[] newArray(int size) { + return new SessionInfo[size]; + } + }; } } diff --git a/core/java/android/content/pm/PackageInstallerParams.aidl b/core/java/android/content/pm/PackageInstallerParams.aidl deleted file mode 100644 index b3dde21f0b86b..0000000000000 --- a/core/java/android/content/pm/PackageInstallerParams.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2014 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; - -parcelable PackageInstallerParams; diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index b957a1555155c..5a54767205413 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -28,8 +28,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; -import android.content.pm.PackageInstaller.CommitCallback; -import android.content.pm.PackageInstaller.UninstallCallback; import android.content.pm.PackageParser.PackageParserException; import android.content.res.Resources; import android.content.res.XmlResourceParser; @@ -3796,6 +3794,16 @@ public abstract class PackageManager { /** {@hide} */ public abstract boolean isPackageAvailable(String packageName); + /** {@hide} */ + public static String installStatusToString(int status, String msg) { + final String str = installStatusToString(status); + if (msg != null) { + return str + ": " + msg; + } else { + return str; + } + } + /** {@hide} */ public static String installStatusToString(int status) { switch (status) { @@ -3845,49 +3853,60 @@ public abstract class PackageManager { } /** {@hide} */ - public static int installStatusToFailureReason(int status) { + public static int installStatusToPublicStatus(int status) { switch (status) { - case INSTALL_FAILED_ALREADY_EXISTS: return CommitCallback.FAILURE_CONFLICT; - case INSTALL_FAILED_INVALID_APK: return CommitCallback.FAILURE_INVALID; - case INSTALL_FAILED_INVALID_URI: return CommitCallback.FAILURE_INVALID; - case INSTALL_FAILED_INSUFFICIENT_STORAGE: return CommitCallback.FAILURE_STORAGE; - case INSTALL_FAILED_DUPLICATE_PACKAGE: return CommitCallback.FAILURE_CONFLICT; - case INSTALL_FAILED_NO_SHARED_USER: return CommitCallback.FAILURE_CONFLICT; - case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return CommitCallback.FAILURE_CONFLICT; - case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return CommitCallback.FAILURE_CONFLICT; - case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return CommitCallback.FAILURE_INCOMPATIBLE; - case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return CommitCallback.FAILURE_CONFLICT; - case INSTALL_FAILED_DEXOPT: return CommitCallback.FAILURE_INVALID; - case INSTALL_FAILED_OLDER_SDK: return CommitCallback.FAILURE_INCOMPATIBLE; - case INSTALL_FAILED_CONFLICTING_PROVIDER: return CommitCallback.FAILURE_CONFLICT; - case INSTALL_FAILED_NEWER_SDK: return CommitCallback.FAILURE_INCOMPATIBLE; - case INSTALL_FAILED_TEST_ONLY: return CommitCallback.FAILURE_INVALID; - case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return CommitCallback.FAILURE_INCOMPATIBLE; - case INSTALL_FAILED_MISSING_FEATURE: return CommitCallback.FAILURE_INCOMPATIBLE; - case INSTALL_FAILED_CONTAINER_ERROR: return CommitCallback.FAILURE_STORAGE; - case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return CommitCallback.FAILURE_STORAGE; - case INSTALL_FAILED_MEDIA_UNAVAILABLE: return CommitCallback.FAILURE_STORAGE; - case INSTALL_FAILED_VERIFICATION_TIMEOUT: return CommitCallback.FAILURE_ABORTED; - case INSTALL_FAILED_VERIFICATION_FAILURE: return CommitCallback.FAILURE_ABORTED; - case INSTALL_FAILED_PACKAGE_CHANGED: return CommitCallback.FAILURE_INVALID; - case INSTALL_FAILED_UID_CHANGED: return CommitCallback.FAILURE_INVALID; - case INSTALL_FAILED_VERSION_DOWNGRADE: return CommitCallback.FAILURE_INVALID; - case INSTALL_PARSE_FAILED_NOT_APK: return CommitCallback.FAILURE_INVALID; - case INSTALL_PARSE_FAILED_BAD_MANIFEST: return CommitCallback.FAILURE_INVALID; - case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return CommitCallback.FAILURE_INVALID; - case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return CommitCallback.FAILURE_INVALID; - case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return CommitCallback.FAILURE_INVALID; - case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return CommitCallback.FAILURE_INVALID; - case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return CommitCallback.FAILURE_INVALID; - case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return CommitCallback.FAILURE_INVALID; - case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return CommitCallback.FAILURE_INVALID; - case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return CommitCallback.FAILURE_INVALID; - case INSTALL_FAILED_INTERNAL_ERROR: return CommitCallback.FAILURE_UNKNOWN; - case INSTALL_FAILED_USER_RESTRICTED: return CommitCallback.FAILURE_INCOMPATIBLE; - case INSTALL_FAILED_DUPLICATE_PERMISSION: return CommitCallback.FAILURE_CONFLICT; - case INSTALL_FAILED_NO_MATCHING_ABIS: return CommitCallback.FAILURE_INCOMPATIBLE; - case INSTALL_FAILED_ABORTED: return CommitCallback.FAILURE_ABORTED; - default: return CommitCallback.FAILURE_UNKNOWN; + case INSTALL_SUCCEEDED: return PackageInstaller.STATUS_SUCCESS; + case INSTALL_FAILED_ALREADY_EXISTS: return PackageInstaller.STATUS_FAILURE_CONFLICT; + case INSTALL_FAILED_INVALID_APK: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_FAILED_INVALID_URI: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_FAILED_INSUFFICIENT_STORAGE: return PackageInstaller.STATUS_FAILURE_STORAGE; + case INSTALL_FAILED_DUPLICATE_PACKAGE: return PackageInstaller.STATUS_FAILURE_CONFLICT; + case INSTALL_FAILED_NO_SHARED_USER: return PackageInstaller.STATUS_FAILURE_CONFLICT; + case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return PackageInstaller.STATUS_FAILURE_CONFLICT; + case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return PackageInstaller.STATUS_FAILURE_CONFLICT; + case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return PackageInstaller.STATUS_FAILURE_CONFLICT; + case INSTALL_FAILED_DEXOPT: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_FAILED_OLDER_SDK: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_CONFLICTING_PROVIDER: return PackageInstaller.STATUS_FAILURE_CONFLICT; + case INSTALL_FAILED_NEWER_SDK: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_TEST_ONLY: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_MISSING_FEATURE: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_CONTAINER_ERROR: return PackageInstaller.STATUS_FAILURE_STORAGE; + case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return PackageInstaller.STATUS_FAILURE_STORAGE; + case INSTALL_FAILED_MEDIA_UNAVAILABLE: return PackageInstaller.STATUS_FAILURE_STORAGE; + case INSTALL_FAILED_VERIFICATION_TIMEOUT: return PackageInstaller.STATUS_FAILURE_ABORTED; + case INSTALL_FAILED_VERIFICATION_FAILURE: return PackageInstaller.STATUS_FAILURE_ABORTED; + case INSTALL_FAILED_PACKAGE_CHANGED: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_FAILED_UID_CHANGED: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_FAILED_VERSION_DOWNGRADE: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_PARSE_FAILED_NOT_APK: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_PARSE_FAILED_BAD_MANIFEST: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_FAILED_INTERNAL_ERROR: return PackageInstaller.STATUS_FAILURE; + case INSTALL_FAILED_USER_RESTRICTED: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_DUPLICATE_PERMISSION: return PackageInstaller.STATUS_FAILURE_CONFLICT; + case INSTALL_FAILED_NO_MATCHING_ABIS: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED; + default: return PackageInstaller.STATUS_FAILURE; + } + } + + /** {@hide} */ + public static String deleteStatusToString(int status, String msg) { + final String str = deleteStatusToString(status); + if (msg != null) { + return str + ": " + msg; + } else { + return str; } } @@ -3905,14 +3924,15 @@ public abstract class PackageManager { } /** {@hide} */ - public static int deleteStatusToFailureReason(int status) { + public static int deleteStatusToPublicStatus(int status) { switch (status) { - case DELETE_FAILED_INTERNAL_ERROR: return UninstallCallback.FAILURE_UNKNOWN; - case DELETE_FAILED_DEVICE_POLICY_MANAGER: return UninstallCallback.FAILURE_BLOCKED; - case DELETE_FAILED_USER_RESTRICTED: return UninstallCallback.FAILURE_BLOCKED; - case DELETE_FAILED_OWNER_BLOCKED: return UninstallCallback.FAILURE_BLOCKED; - case DELETE_FAILED_ABORTED: return UninstallCallback.FAILURE_ABORTED; - default: return UninstallCallback.FAILURE_UNKNOWN; + case DELETE_SUCCEEDED: return PackageInstaller.STATUS_SUCCESS; + case DELETE_FAILED_INTERNAL_ERROR: return PackageInstaller.STATUS_FAILURE; + case DELETE_FAILED_DEVICE_POLICY_MANAGER: return PackageInstaller.STATUS_FAILURE_BLOCKED; + case DELETE_FAILED_USER_RESTRICTED: return PackageInstaller.STATUS_FAILURE_BLOCKED; + case DELETE_FAILED_OWNER_BLOCKED: return PackageInstaller.STATUS_FAILURE_BLOCKED; + case DELETE_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED; + default: return PackageInstaller.STATUS_FAILURE; } } diff --git a/core/java/android/content/pm/VerificationParams.java b/core/java/android/content/pm/VerificationParams.java index bf1f77f6826e9..e5119b621ee56 100644 --- a/core/java/android/content/pm/VerificationParams.java +++ b/core/java/android/content/pm/VerificationParams.java @@ -24,7 +24,7 @@ import android.os.Parcelable; /** * Represents verification parameters used to verify packages to be installed. * - * @deprecated callers should migrate to {@link PackageInstallerParams}. + * @deprecated callers should migrate to {@link PackageInstaller}. * @hide */ @Deprecated diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index c7e3fb74d2ec8..dca8ad421ba25 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -36,19 +36,23 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.app.ActivityManager; import android.app.AppOpsManager; +import android.app.PackageDeleteObserver; +import android.app.PackageInstallObserver; import android.content.Context; import android.content.Intent; -import android.content.pm.IPackageDeleteObserver2; +import android.content.IntentSender; +import android.content.IntentSender.SendIntentException; import android.content.pm.IPackageInstaller; import android.content.pm.IPackageInstallerCallback; import android.content.pm.IPackageInstallerSession; -import android.content.pm.InstallSessionInfo; -import android.content.pm.InstallSessionParams; import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstaller.SessionInfo; +import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Binder; +import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; @@ -63,6 +67,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.system.ErrnoException; import android.system.Os; +import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArraySet; import android.util.AtomicFile; @@ -279,8 +284,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { final File sessionStageDir = new File(readStringAttribute(in, ATTR_SESSION_STAGE_DIR)); final boolean sealed = readBooleanAttribute(in, ATTR_SEALED); - final InstallSessionParams params = new InstallSessionParams( - InstallSessionParams.MODE_INVALID); + final SessionParams params = new SessionParams( + SessionParams.MODE_INVALID); params.mode = readIntAttribute(in, ATTR_MODE); params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS); params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION); @@ -292,9 +297,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub { params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI); params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE); - return new PackageInstallerSession(mInternalCallback, mPm, mInstallThread.getLooper(), - sessionId, userId, installerPackageName, params, createdMillis, sessionStageDir, - sealed); + return new PackageInstallerSession(mInternalCallback, mContext, mPm, + mInstallThread.getLooper(), sessionId, userId, installerPackageName, params, + createdMillis, sessionStageDir, sealed); } private void writeSessionsLocked() { @@ -326,7 +331,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session) throws IOException { - final InstallSessionParams params = session.params; + final SessionParams params = session.params; final Snapshot snapshot = session.snapshot(); out.startTag(null, TAG_SESSION); @@ -366,7 +371,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public int createSession(InstallSessionParams params, String installerPackageName, int userId) { + public int createSession(SessionParams params, String installerPackageName, int userId) { final int callingUid = Binder.getCallingUid(); mPm.enforceCrossUserPermission(callingUid, userId, true, "createSession"); @@ -389,8 +394,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } switch (params.mode) { - case InstallSessionParams.MODE_FULL_INSTALL: - case InstallSessionParams.MODE_INHERIT_EXISTING: + case SessionParams.MODE_FULL_INSTALL: + case SessionParams.MODE_INHERIT_EXISTING: break; default: throw new IllegalArgumentException("Params must have valid mode set"); @@ -437,7 +442,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { final long createdMillis = System.currentTimeMillis(); final File sessionStageDir = prepareSessionStageDir(sessionId); - session = new PackageInstallerSession(mInternalCallback, mPm, + session = new PackageInstallerSession(mInternalCallback, mContext, mPm, mInstallThread.getLooper(), sessionId, userId, installerPackageName, params, createdMillis, sessionStageDir, false); mSessions.put(sessionId, session); @@ -501,7 +506,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public InstallSessionInfo getSessionInfo(int sessionId) { + public SessionInfo getSessionInfo(int sessionId) { synchronized (mSessions) { final PackageInstallerSession session = mSessions.get(sessionId); if (!isCallingUidOwner(session)) { @@ -512,11 +517,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public List getAllSessions(int userId) { + public List getAllSessions(int userId) { mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getAllSessions"); enforceCallerCanReadSessions(); - final List result = new ArrayList<>(); + final List result = new ArrayList<>(); synchronized (mSessions) { for (int i = 0; i < mSessions.size(); i++) { final PackageInstallerSession session = mSessions.valueAt(i); @@ -529,11 +534,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public List getMySessions(String installerPackageName, int userId) { + public List getMySessions(String installerPackageName, int userId) { mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getMySessions"); mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName); - final List result = new ArrayList<>(); + final List result = new ArrayList<>(); synchronized (mSessions) { for (int i = 0; i < mSessions.size(); i++) { final PackageInstallerSession session = mSessions.valueAt(i); @@ -547,36 +552,25 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public void uninstall(String packageName, int flags, IPackageDeleteObserver2 observer, - int userId) { + public void uninstall(String packageName, int flags, IntentSender statusReceiver, int userId) { mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall"); + final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, + statusReceiver); if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES) == PackageManager.PERMISSION_GRANTED) { // Sweet, call straight through! - mPm.deletePackage(packageName, observer, userId, flags); + mPm.deletePackage(packageName, adapter.getBinder(), userId, flags); } else { // Take a short detour to confirm with user final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); intent.setData(Uri.fromParts("package", packageName, null)); - intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder()); - try { - observer.onUserActionRequired(intent); - } catch (RemoteException ignored) { - } + intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder()); + adapter.onUserActionRequired(intent); } } - @Override - public void uninstallSplit(String basePackageName, String overlayName, int flags, - IPackageDeleteObserver2 observer, int userId) { - mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstallSplit"); - - // TODO: flesh out once PM has split support - throw new UnsupportedOperationException(); - } - @Override public void setPermissionsResult(int sessionId, boolean accepted) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG); @@ -636,6 +630,87 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } } + static class PackageDeleteObserverAdapter extends PackageDeleteObserver { + private final Context mContext; + private final IntentSender mTarget; + + public PackageDeleteObserverAdapter(Context context, IntentSender target) { + mContext = context; + mTarget = target; + } + + @Override + public void onUserActionRequired(Intent intent) { + final Intent fillIn = new Intent(); + fillIn.putExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_USER_ACTION_REQUIRED); + fillIn.putExtra(Intent.EXTRA_INTENT, intent); + try { + mTarget.sendIntent(mContext, 0, fillIn, null, null); + } catch (SendIntentException ignored) { + } + } + + @Override + public void onPackageDeleted(String basePackageName, int returnCode, String msg) { + final Intent fillIn = new Intent(); + fillIn.putExtra(PackageInstaller.EXTRA_STATUS, + PackageManager.deleteStatusToPublicStatus(returnCode)); + fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, + PackageManager.deleteStatusToString(returnCode, msg)); + fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); + try { + mTarget.sendIntent(mContext, 0, fillIn, null, null); + } catch (SendIntentException ignored) { + } + } + } + + static class PackageInstallObserverAdapter extends PackageInstallObserver { + private final Context mContext; + private final IntentSender mTarget; + + public PackageInstallObserverAdapter(Context context, IntentSender target) { + mContext = context; + mTarget = target; + } + + @Override + public void onUserActionRequired(Intent intent) { + final Intent fillIn = new Intent(); + fillIn.putExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_USER_ACTION_REQUIRED); + fillIn.putExtra(Intent.EXTRA_INTENT, intent); + try { + mTarget.sendIntent(mContext, 0, fillIn, null, null); + } catch (SendIntentException ignored) { + } + } + + @Override + public void onPackageInstalled(String basePackageName, int returnCode, String msg, + Bundle extras) { + final Intent fillIn = new Intent(); + fillIn.putExtra(PackageInstaller.EXTRA_STATUS, + PackageManager.installStatusToPublicStatus(returnCode)); + fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, + PackageManager.installStatusToString(returnCode, msg)); + fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); + if (extras != null) { + final String existing = extras.getString( + PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE); + if (!TextUtils.isEmpty(existing)) { + fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAMES, new String[] { + existing }); + } + } + try { + mTarget.sendIntent(mContext, 0, fillIn, null, null); + } catch (SendIntentException ignored) { + } + } + } + private static class Callbacks extends Handler { private static final int MSG_SESSION_CREATED = 1; private static final int MSG_SESSION_OPENED = 2; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index a3184f027093d..5ef24f2ab6ac4 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -25,13 +25,15 @@ import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDONLY; import static android.system.OsConstants.O_WRONLY; +import android.content.Context; import android.content.Intent; +import android.content.IntentSender; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageInstallObserver2; import android.content.pm.IPackageInstallerSession; -import android.content.pm.InstallSessionInfo; -import android.content.pm.InstallSessionParams; import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstaller.SessionInfo; +import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.ApkLite; @@ -59,6 +61,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; +import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter; import libcore.io.Libcore; @@ -81,13 +84,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // TODO: treat INHERIT_EXISTING as installExistingPackage() private final PackageInstallerService.InternalCallback mCallback; + private final Context mContext; private final PackageManagerService mPm; private final Handler mHandler; final int sessionId; final int userId; final String installerPackageName; - final InstallSessionParams params; + final SessionParams params; final long createdMillis; final File sessionStageDir; @@ -159,10 +163,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { }; public PackageInstallerSession(PackageInstallerService.InternalCallback callback, - PackageManagerService pm, Looper looper, int sessionId, int userId, - String installerPackageName, InstallSessionParams params, long createdMillis, + Context context, PackageManagerService pm, Looper looper, int sessionId, int userId, + String installerPackageName, SessionParams params, long createdMillis, File sessionStageDir, boolean sealed) { mCallback = callback; + mContext = context; mPm = pm; mHandler = new Handler(looper, mHandlerCallback); @@ -188,8 +193,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { computeProgressLocked(); } - public InstallSessionInfo generateInfo() { - final InstallSessionInfo info = new InstallSessionInfo(); + public SessionInfo generateInfo() { + final SessionInfo info = new SessionInfo(); info.sessionId = sessionId; info.installerPackageName = installerPackageName; @@ -246,8 +251,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @Override - public String[] list() { - assertNotSealed("list"); + public String[] getNames() { + assertNotSealed("getNames"); return sessionStageDir.list(); } @@ -337,9 +342,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @Override - public void commit(IPackageInstallObserver2 observer) { - Preconditions.checkNotNull(observer); - mHandler.obtainMessage(MSG_COMMIT, observer).sendToTarget(); + public void commit(IntentSender statusReceiver) { + Preconditions.checkNotNull(statusReceiver); + + final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext, + statusReceiver); + mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget(); } private void commitLocked() throws PackageManagerException { @@ -385,7 +393,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Inherit any packages and native libraries from existing install that // haven't been overridden. - if (params.mode == InstallSessionParams.MODE_INHERIT_EXISTING) { + if (params.mode == SessionParams.MODE_INHERIT_EXISTING) { spliceExistingFilesIntoStage(); } @@ -396,7 +404,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // We've reached point of no return; call into PMS to install the stage. // Regardless of success or failure we always destroy session. - final IPackageInstallObserver2 remoteObserver = mRemoteObserver; final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() { @Override public void onUserActionRequired(Intent intent) { @@ -488,7 +495,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // currently relying on PMS to do this. // TODO: teach about compatible upgrade keysets. - if (params.mode == InstallSessionParams.MODE_FULL_INSTALL) { + if (params.mode == SessionParams.MODE_FULL_INSTALL) { // Full installs must include a base package if (!seenSplits.contains(null)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 304441c02d4af..63f3c0f7b4ca6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -107,12 +107,12 @@ import android.content.pm.IPackageInstaller; import android.content.pm.IPackageManager; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; -import android.content.pm.InstallSessionParams; import android.content.pm.InstrumentationInfo; import android.content.pm.ManifestDigest; import android.content.pm.PackageCleanItem; import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; +import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManager.LegacyPackageDeleteObserver; import android.content.pm.PackageParser.ActivityIntentInfo; @@ -7846,7 +7846,7 @@ public class PackageManagerService extends IPackageManager.Stub { } void installStage(String packageName, File stageDir, IPackageInstallObserver2 observer, - InstallSessionParams params, String installerPackageName, int installerUid, + PackageInstaller.SessionParams params, String installerPackageName, int installerUid, UserHandle user) { final VerificationParams verifParams = new VerificationParams(null, params.originatingUri, params.referrerUri, installerUid, null);