diff options
16 files changed, 523 insertions, 129 deletions
@@ -130,6 +130,7 @@ LOCAL_SRC_FILES += \ core/java/android/content/pm/IPackageInstallObserver.aidl \ core/java/android/content/pm/IPackageInstallObserver2.aidl \ core/java/android/content/pm/IPackageInstaller.aidl \ + core/java/android/content/pm/IPackageInstallerObserver.aidl \ core/java/android/content/pm/IPackageInstallerSession.aidl \ core/java/android/content/pm/IPackageManager.aidl \ core/java/android/content/pm/IPackageMoveObserver.aidl \ diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 92e9290..6cca03b 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -27,10 +27,11 @@ import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstaller; import android.content.pm.IPackageManager; +import android.content.pm.InstallSessionParams; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; -import android.content.pm.PackageInstallerParams; +import android.content.pm.PackageInstaller.InstallResultCallback; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; @@ -768,6 +769,31 @@ public final class Pm { } } + class LocalInstallResultCallback extends InstallResultCallback { + 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 onSuccess() { + setResult(true, null); + } + + @Override + public void onFailure(String msg) { + setResult(false, msg); + } + } + /** * Converts a failure code into a string by using reflection to find a matching constant * in PackageManager. @@ -989,7 +1015,7 @@ public final class Pm { private void runInstallCreate() throws RemoteException { String installerPackageName = null; - final PackageInstallerParams params = new PackageInstallerParams(); + final InstallSessionParams params = new InstallSessionParams(); params.installFlags = PackageManager.INSTALL_ALL_USERS; params.fullInstall = true; @@ -1084,21 +1110,21 @@ public final class Pm { try { session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); - final LocalPackageInstallObserver observer = new LocalPackageInstallObserver(); - session.install(observer); + final LocalInstallResultCallback callback = new LocalInstallResultCallback(); + session.install(callback); - synchronized (observer) { - while (!observer.finished) { + synchronized (callback) { + while (!callback.finished) { try { - observer.wait(); + callback.wait(); } catch (InterruptedException e) { } } - if (observer.result != PackageManager.INSTALL_SUCCEEDED) { - throw new IllegalStateException( - "Failure [" + installFailureToString(observer) + "]"); + if (!callback.success) { + throw new IllegalStateException("Failure [" + callback.msg + "]"); } } + System.out.println("Success"); } finally { IoUtils.closeQuietly(session); diff --git a/core/java/android/app/PackageInstallObserver.java b/core/java/android/app/PackageInstallObserver.java index 941efbd..7117111 100644 --- a/core/java/android/app/PackageInstallObserver.java +++ b/core/java/android/app/PackageInstallObserver.java @@ -23,13 +23,14 @@ import android.os.Bundle; public class PackageInstallObserver { private final IPackageInstallObserver2.Stub mBinder = new IPackageInstallObserver2.Stub() { @Override - public void packageInstalled(String basePackageName, Bundle extras, int returnCode) { + public void packageInstalled(String basePackageName, Bundle extras, int returnCode, + String msg) { PackageInstallObserver.this.packageInstalled(basePackageName, extras, returnCode); } }; /** {@hide} */ - public IPackageInstallObserver2.Stub getBinder() { + public IPackageInstallObserver2 getBinder() { return mBinder; } @@ -50,4 +51,9 @@ public class PackageInstallObserver { */ public void packageInstalled(String basePackageName, Bundle extras, int returnCode) { } + + public void packageInstalled(String basePackageName, Bundle extras, int returnCode, + String msg) { + packageInstalled(basePackageName, extras, returnCode); + } } diff --git a/core/java/android/app/PackageUninstallObserver.java b/core/java/android/app/PackageUninstallObserver.java index 0a960a7..83fc380 100644 --- a/core/java/android/app/PackageUninstallObserver.java +++ b/core/java/android/app/PackageUninstallObserver.java @@ -28,7 +28,7 @@ public class PackageUninstallObserver { }; /** {@hide} */ - public IPackageDeleteObserver.Stub getBinder() { + public IPackageDeleteObserver getBinder() { return mBinder; } diff --git a/core/java/android/content/pm/IPackageInstallObserver2.aidl b/core/java/android/content/pm/IPackageInstallObserver2.aidl index 7205ce7..824d730 100644 --- a/core/java/android/content/pm/IPackageInstallObserver2.aidl +++ b/core/java/android/content/pm/IPackageInstallObserver2.aidl @@ -40,5 +40,5 @@ oneway interface IPackageInstallObserver2 { * </tr> * </table> */ - void packageInstalled(String basePackageName, in Bundle extras, int returnCode); + void packageInstalled(String basePackageName, in Bundle extras, int returnCode, String msg); } diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 4d6ee64..32460c9 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -17,17 +17,22 @@ package android.content.pm; import android.content.pm.IPackageDeleteObserver; +import android.content.pm.IPackageInstallerObserver; import android.content.pm.IPackageInstallerSession; -import android.content.pm.PackageInstallerParams; +import android.content.pm.InstallSessionInfo; +import android.content.pm.InstallSessionParams; import android.os.ParcelFileDescriptor; /** {@hide} */ interface IPackageInstaller { - int createSession(String installerPackageName, in PackageInstallerParams params, int userId); + int createSession(String installerPackageName, in InstallSessionParams params, int userId); IPackageInstallerSession openSession(int sessionId); - int[] getSessions(String installerPackageName, int userId); + List<InstallSessionInfo> getSessions(int userId); - void uninstall(String basePackageName, int flags, in IPackageDeleteObserver observer, int userId); - void uninstallSplit(String basePackageName, String splitName, int flags, in IPackageDeleteObserver observer, int userId); + void registerObserver(IPackageInstallerObserver observer, int userId); + void unregisterObserver(IPackageInstallerObserver observer, int userId); + + void uninstall(String packageName, int flags, in IPackageDeleteObserver observer, int userId); + void uninstallSplit(String packageName, String splitName, int flags, in IPackageDeleteObserver observer, int userId); } diff --git a/core/java/android/content/pm/IPackageInstallerObserver.aidl b/core/java/android/content/pm/IPackageInstallerObserver.aidl new file mode 100644 index 0000000..85660e4 --- /dev/null +++ b/core/java/android/content/pm/IPackageInstallerObserver.aidl @@ -0,0 +1,26 @@ +/* + * 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.content.pm.InstallSessionInfo; + +/** {@hide} */ +oneway interface IPackageInstallerObserver { + void onSessionCreated(in InstallSessionInfo info); + void onSessionProgress(int sessionId, int progress); + void onSessionFinished(int sessionId, boolean success); +} diff --git a/core/java/android/content/pm/InstallSessionInfo.aidl b/core/java/android/content/pm/InstallSessionInfo.aidl new file mode 100644 index 0000000..3d21bbd --- /dev/null +++ b/core/java/android/content/pm/InstallSessionInfo.aidl @@ -0,0 +1,19 @@ +/* + * 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 InstallSessionInfo; diff --git a/core/java/android/content/pm/InstallSessionInfo.java b/core/java/android/content/pm/InstallSessionInfo.java new file mode 100644 index 0000000..45606d1 --- /dev/null +++ b/core/java/android/content/pm/InstallSessionInfo.java @@ -0,0 +1,79 @@ +/* + * 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.graphics.Bitmap; +import android.os.Parcel; +import android.os.Parcelable; + +/** {@hide} */ +public class InstallSessionInfo implements Parcelable { + public int sessionId; + public String installerPackageName; + public int progress; + + public boolean fullInstall; + public String packageName; + public Bitmap icon; + public CharSequence title; + + /** {@hide} */ + public InstallSessionInfo() { + } + + /** {@hide} */ + public InstallSessionInfo(Parcel source) { + sessionId = source.readInt(); + installerPackageName = source.readString(); + progress = source.readInt(); + + fullInstall = source.readInt() != 0; + packageName = source.readString(); + icon = source.readParcelable(null); + title = source.readString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(sessionId); + dest.writeString(installerPackageName); + dest.writeInt(progress); + + dest.writeInt(fullInstall ? 1 : 0); + dest.writeString(packageName); + dest.writeParcelable(icon, flags); + dest.writeString(title != null ? title.toString() : null); + } + + public static final Parcelable.Creator<InstallSessionInfo> + CREATOR = new Parcelable.Creator<InstallSessionInfo>() { + @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 new file mode 100644 index 0000000..81b7574 --- /dev/null +++ b/core/java/android/content/pm/InstallSessionParams.aidl @@ -0,0 +1,19 @@ +/* + * 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/PackageInstallerParams.java b/core/java/android/content/pm/InstallSessionParams.java index 527edee..f683523 100644 --- a/core/java/android/content/pm/PackageInstallerParams.java +++ b/core/java/android/content/pm/InstallSessionParams.java @@ -21,12 +21,8 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; -/** - * Parameters that define an installation session. - * - * {@hide} - */ -public class PackageInstallerParams implements Parcelable { +/** {@hide} */ +public class InstallSessionParams implements Parcelable { // TODO: extend to support remaining VerificationParams @@ -41,11 +37,11 @@ public class PackageInstallerParams implements Parcelable { /** {@hide} */ public long deltaSize = -1; /** {@hide} */ - public String basePackageName; + public String packageName; /** {@hide} */ public Bitmap icon; /** {@hide} */ - public String title; + public CharSequence title; /** {@hide} */ public Uri originatingUri; /** {@hide} */ @@ -53,20 +49,18 @@ public class PackageInstallerParams implements Parcelable { /** {@hide} */ public String abiOverride; - public PackageInstallerParams() { + public InstallSessionParams() { } /** {@hide} */ - public PackageInstallerParams(Parcel source) { + public InstallSessionParams(Parcel source) { fullInstall = source.readInt() != 0; installFlags = source.readInt(); installLocation = source.readInt(); signatures = (Signature[]) source.readParcelableArray(null); deltaSize = source.readLong(); - basePackageName = source.readString(); - if (source.readInt() != 0) { - icon = Bitmap.CREATOR.createFromParcel(source); - } + packageName = source.readString(); + icon = source.readParcelable(null); title = source.readString(); originatingUri = source.readParcelable(null); referrerUri = source.readParcelable(null); @@ -93,8 +87,8 @@ public class PackageInstallerParams implements Parcelable { this.deltaSize = deltaSize; } - public void setBasePackageName(String basePackageName) { - this.basePackageName = basePackageName; + public void setPackageName(String packageName) { + this.packageName = packageName; } public void setIcon(Bitmap icon) { @@ -102,7 +96,7 @@ public class PackageInstallerParams implements Parcelable { } public void setTitle(CharSequence title) { - this.title = (title != null) ? title.toString() : null; + this.title = title; } public void setOriginatingUri(Uri originatingUri) { @@ -125,29 +119,24 @@ public class PackageInstallerParams implements Parcelable { dest.writeInt(installLocation); dest.writeParcelableArray(signatures, flags); dest.writeLong(deltaSize); - dest.writeString(basePackageName); - if (icon != null) { - dest.writeInt(1); - icon.writeToParcel(dest, flags); - } else { - dest.writeInt(0); - } - dest.writeString(title); + dest.writeString(packageName); + dest.writeParcelable(icon, flags); + dest.writeString(title != null ? title.toString() : null); dest.writeParcelable(originatingUri, flags); dest.writeParcelable(referrerUri, flags); dest.writeString(abiOverride); } - public static final Parcelable.Creator<PackageInstallerParams> - CREATOR = new Parcelable.Creator<PackageInstallerParams>() { + public static final Parcelable.Creator<InstallSessionParams> + CREATOR = new Parcelable.Creator<InstallSessionParams>() { @Override - public PackageInstallerParams createFromParcel(Parcel p) { - return new PackageInstallerParams(p); + public InstallSessionParams createFromParcel(Parcel p) { + return new InstallSessionParams(p); } @Override - public PackageInstallerParams[] newArray(int size) { - return new PackageInstallerParams[size]; + public InstallSessionParams[] newArray(int size) { + return new InstallSessionParams[size]; } }; } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index a60a2fe..9d756f7 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -19,12 +19,14 @@ package android.content.pm; import android.app.PackageInstallObserver; import android.app.PackageUninstallObserver; import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; import android.os.FileBridge; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import java.io.Closeable; import java.io.OutputStream; +import java.util.List; /** {@hide} */ public class PackageInstaller { @@ -42,9 +44,9 @@ public class PackageInstaller { mUserId = userId; } - public boolean isPackageAvailable(String basePackageName) { + public boolean isPackageAvailable(String packageName) { try { - final ApplicationInfo info = mPm.getApplicationInfo(basePackageName, + final ApplicationInfo info = mPm.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES); return ((info.flags & ApplicationInfo.FLAG_INSTALLED) != 0); } catch (NameNotFoundException e) { @@ -52,17 +54,17 @@ public class PackageInstaller { } } - public void installAvailablePackage(String basePackageName, PackageInstallObserver observer) { + public void installAvailablePackage(String packageName, PackageInstallObserver observer) { int returnCode; try { - returnCode = mPm.installExistingPackage(basePackageName); + returnCode = mPm.installExistingPackage(packageName); } catch (NameNotFoundException e) { returnCode = PackageManager.INSTALL_FAILED_PACKAGE_CHANGED; } - observer.packageInstalled(basePackageName, null, returnCode); + observer.packageInstalled(packageName, null, returnCode); } - public int createSession(PackageInstallerParams params) { + public int createSession(InstallSessionParams params) { try { return mInstaller.createSession(mInstallerPackageName, params, mUserId); } catch (RemoteException e) { @@ -78,26 +80,74 @@ public class PackageInstaller { } } - public int[] getSessions() { + public List<InstallSessionInfo> getSessions() { + // TODO: filter based on caller + // TODO: let launcher app see all active sessions try { - return mInstaller.getSessions(mInstallerPackageName, mUserId); + return mInstaller.getSessions(mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } } - public void uninstall(String basePackageName, PackageUninstallObserver observer) { + public void uninstall(String packageName, UninstallResultCallback callback) { try { - mInstaller.uninstall(basePackageName, 0, observer.getBinder(), mUserId); + mInstaller.uninstall(packageName, 0, + new UninstallResultCallbackDelegate(callback).getBinder(), mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } } - public void uninstall(String basePackageName, String splitName, - PackageUninstallObserver observer) { + public void uninstall(String packageName, String splitName, UninstallResultCallback callback) { try { - mInstaller.uninstallSplit(basePackageName, splitName, 0, observer.getBinder(), mUserId); + mInstaller.uninstallSplit(packageName, splitName, 0, + new UninstallResultCallbackDelegate(callback).getBinder(), mUserId); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + public static abstract class SessionObserver { + private final IPackageInstallerObserver.Stub mBinder = new IPackageInstallerObserver.Stub() { + @Override + public void onSessionCreated(InstallSessionInfo info) { + SessionObserver.this.onCreated(info); + } + + @Override + public void onSessionProgress(int sessionId, int progress) { + SessionObserver.this.onProgress(sessionId, progress); + } + + @Override + public void onSessionFinished(int sessionId, boolean success) { + SessionObserver.this.onFinished(sessionId, success); + } + }; + + /** {@hide} */ + public IPackageInstallerObserver getBinder() { + return mBinder; + } + + public abstract void onCreated(InstallSessionInfo info); + public abstract void onProgress(int sessionId, int progress); + public abstract void onFinished(int sessionId, boolean success); + } + + public void registerObserver(SessionObserver observer) { + // TODO: consider restricting to current launcher app + try { + mInstaller.registerObserver(observer.getBinder(), mUserId); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + public void unregisterObserver(SessionObserver observer) { + try { + mInstaller.unregisterObserver(observer.getBinder(), mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -147,9 +197,9 @@ public class PackageInstaller { } } - public void install(PackageInstallObserver observer) { + public void install(InstallResultCallback callback) { try { - mSession.install(observer.getBinder()); + mSession.install(new InstallResultCallbackDelegate(callback).getBinder()); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -168,4 +218,143 @@ public class PackageInstaller { } } } + + public static abstract class UninstallResultCallback { + public abstract void onSuccess(); + public abstract void onFailure(String msg); + } + + private static class UninstallResultCallbackDelegate extends PackageUninstallObserver { + private final UninstallResultCallback target; + + public UninstallResultCallbackDelegate(UninstallResultCallback target) { + this.target = target; + } + + @Override + public void onUninstallFinished(String basePackageName, int returnCode) { + final String msg = null; + + switch (returnCode) { + case PackageManager.DELETE_SUCCEEDED: target.onSuccess(); break; + case PackageManager.DELETE_FAILED_INTERNAL_ERROR: target.onFailure("DELETE_FAILED_INTERNAL_ERROR: " + msg); break; + case PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER: target.onFailure("DELETE_FAILED_DEVICE_POLICY_MANAGER: " + msg); break; + case PackageManager.DELETE_FAILED_USER_RESTRICTED: target.onFailure("DELETE_FAILED_USER_RESTRICTED: " + msg); break; + case PackageManager.DELETE_FAILED_OWNER_BLOCKED: target.onFailure("DELETE_FAILED_OWNER_BLOCKED: " + msg); break; + default: target.onFailure(msg); break; + } + } + } + + public static abstract class InstallResultCallback { + /** + * The session installed successfully. + */ + public abstract void onSuccess(); + + /** + * General unclassified failure. You may be interested in overriding + * more granular classifications. + */ + public abstract void onFailure(String msg); + + /** + * 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. + */ + public void onFailureInvalid(String msg) { + onFailure(msg); + } + + /** + * 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. + */ + public void onFailureConflict(String msg, String packageName) { + onFailure(msg); + } + + /** + * 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. + */ + public void onFailureStorage(String msg) { + onFailure(msg); + } + + /** + * 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. + */ + public void onFailureIncompatible(String msg) { + onFailure(msg); + } + } + + private static class InstallResultCallbackDelegate extends PackageInstallObserver { + private final InstallResultCallback target; + + public InstallResultCallbackDelegate(InstallResultCallback target) { + this.target = target; + } + + @Override + public void packageInstalled(String basePackageName, Bundle extras, int returnCode, + String msg) { + final String otherPackage = null; + + switch (returnCode) { + case PackageManager.INSTALL_SUCCEEDED: target.onSuccess(); break; + case PackageManager.INSTALL_FAILED_ALREADY_EXISTS: target.onFailureConflict("INSTALL_FAILED_ALREADY_EXISTS: " + msg, otherPackage); break; + case PackageManager.INSTALL_FAILED_INVALID_APK: target.onFailureInvalid("INSTALL_FAILED_INVALID_APK: " + msg); break; + case PackageManager.INSTALL_FAILED_INVALID_URI: target.onFailureInvalid("INSTALL_FAILED_INVALID_URI: " + msg); break; + case PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE: target.onFailureStorage("INSTALL_FAILED_INSUFFICIENT_STORAGE: " + msg); break; + case PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE: target.onFailureConflict("INSTALL_FAILED_DUPLICATE_PACKAGE: " + msg, otherPackage); break; + case PackageManager.INSTALL_FAILED_NO_SHARED_USER: target.onFailureConflict("INSTALL_FAILED_NO_SHARED_USER: " + msg, otherPackage); break; + case PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE: target.onFailureConflict("INSTALL_FAILED_UPDATE_INCOMPATIBLE: " + msg, otherPackage); break; + case PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: target.onFailureConflict("INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: " + msg, otherPackage); break; + case PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY: target.onFailureIncompatible("INSTALL_FAILED_MISSING_SHARED_LIBRARY: " + msg); break; + case PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE: target.onFailureConflict("INSTALL_FAILED_REPLACE_COULDNT_DELETE: " + msg, otherPackage); break; + case PackageManager.INSTALL_FAILED_DEXOPT: target.onFailureInvalid("INSTALL_FAILED_DEXOPT: " + msg); break; + case PackageManager.INSTALL_FAILED_OLDER_SDK: target.onFailureIncompatible("INSTALL_FAILED_OLDER_SDK: " + msg); break; + case PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER: target.onFailureConflict("INSTALL_FAILED_CONFLICTING_PROVIDER: " + msg, otherPackage); break; + case PackageManager.INSTALL_FAILED_NEWER_SDK: target.onFailureIncompatible("INSTALL_FAILED_NEWER_SDK: " + msg); break; + case PackageManager.INSTALL_FAILED_TEST_ONLY: target.onFailureInvalid("INSTALL_FAILED_TEST_ONLY: " + msg); break; + case PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: target.onFailureIncompatible("INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: " + msg); break; + case PackageManager.INSTALL_FAILED_MISSING_FEATURE: target.onFailureIncompatible("INSTALL_FAILED_MISSING_FEATURE: " + msg); break; + case PackageManager.INSTALL_FAILED_CONTAINER_ERROR: target.onFailureStorage("INSTALL_FAILED_CONTAINER_ERROR: " + msg); break; + case PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION: target.onFailureStorage("INSTALL_FAILED_INVALID_INSTALL_LOCATION: " + msg); break; + case PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE: target.onFailureStorage("INSTALL_FAILED_MEDIA_UNAVAILABLE: " + msg); break; + case PackageManager.INSTALL_FAILED_VERIFICATION_TIMEOUT: target.onFailure("INSTALL_FAILED_VERIFICATION_TIMEOUT: " + msg); break; + case PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE: target.onFailure("INSTALL_FAILED_VERIFICATION_FAILURE: " + msg); break; + case PackageManager.INSTALL_FAILED_PACKAGE_CHANGED: target.onFailureInvalid("INSTALL_FAILED_PACKAGE_CHANGED: " + msg); break; + case PackageManager.INSTALL_FAILED_UID_CHANGED: target.onFailureInvalid("INSTALL_FAILED_UID_CHANGED: " + msg); break; + case PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE: target.onFailureInvalid("INSTALL_FAILED_VERSION_DOWNGRADE: " + msg); break; + case PackageManager.INSTALL_PARSE_FAILED_NOT_APK: target.onFailureInvalid("INSTALL_PARSE_FAILED_NOT_APK: " + msg); break; + case PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_MANIFEST: " + msg); break; + case PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: target.onFailureInvalid("INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: " + msg); break; + case PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES: target.onFailureInvalid("INSTALL_PARSE_FAILED_NO_CERTIFICATES: " + msg); break; + case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: target.onFailureInvalid("INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: " + msg); break; + case PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: target.onFailureInvalid("INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: " + msg); break; + case PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: " + msg); break; + case PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: " + msg); break; + case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: target.onFailureInvalid("INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: " + msg); break; + case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY: target.onFailureInvalid("INSTALL_PARSE_FAILED_MANIFEST_EMPTY: " + msg); break; + case PackageManager.INSTALL_FAILED_INTERNAL_ERROR: target.onFailure("INSTALL_FAILED_INTERNAL_ERROR: " + msg); break; + case PackageManager.INSTALL_FAILED_USER_RESTRICTED: target.onFailureIncompatible("INSTALL_FAILED_USER_RESTRICTED: " + msg); break; + case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: target.onFailureConflict("INSTALL_FAILED_DUPLICATE_PERMISSION: " + msg, otherPackage); break; + case PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS: target.onFailureInvalid("INSTALL_FAILED_NO_MATCHING_ABIS: " + msg); break; + default: target.onFailure(msg); break; + } + } + } } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index a0e56f6..7e783eb 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -17,9 +17,9 @@ package android.content.pm; import android.annotation.IntDef; -import android.annotation.SystemApi; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.app.PackageInstallObserver; import android.content.ComponentName; import android.content.Context; @@ -29,13 +29,12 @@ import android.content.IntentSender; import android.content.pm.PackageParser.PackageParserException; import android.content.res.Resources; import android.content.res.XmlResourceParser; -import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Bundle; import android.os.Environment; import android.os.UserHandle; import android.util.AndroidException; -import android.util.DisplayMetrics; import java.io.File; import java.lang.annotation.Retention; @@ -750,7 +749,7 @@ public abstract class PackageManager { * permission that is already defined by some existing package. * * <p>The package name of the app which has already defined the permission is passed to - * a {@link IPackageInstallObserver2}, if any, as the {@link #EXTRA_EXISTING_PACKAGE} + * a {@link PackageInstallObserver}, if any, as the {@link #EXTRA_EXISTING_PACKAGE} * string extra; and the name of the permission being redefined is passed in the * {@link #EXTRA_EXISTING_PERMISSION} string extra. * @hide @@ -1544,7 +1543,7 @@ public abstract class PackageManager { = "android.content.pm.extra.PERMISSION_LIST"; /** - * String extra for {@link IPackageInstallObserver2} in the 'extras' Bundle in case of + * String extra for {@link PackageInstallObserver} in the 'extras' Bundle in case of * {@link #INSTALL_FAILED_DUPLICATE_PERMISSION}. This extra names the package which provides * the existing definition for the permission. * @hide @@ -1553,7 +1552,7 @@ public abstract class PackageManager { = "android.content.pm.extra.FAILURE_EXISTING_PACKAGE"; /** - * String extra for {@link IPackageInstallObserver2} in the 'extras' Bundle in case of + * String extra for {@link PackageInstallObserver} in the 'extras' Bundle in case of * {@link #INSTALL_FAILED_DUPLICATE_PERMISSION}. This extra names the permission that is * being redundantly defined by the package being installed. * @hide @@ -2941,26 +2940,29 @@ public abstract class PackageManager { } /** - * @hide - * - * Install a package. Since this may take a little while, the result will - * be posted back to the given observer. An installation will fail if the calling context - * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the - * package named in the package file's manifest is already installed, or if there's no space - * available on the device. - * - * @param packageURI The location of the package file to install. This can be a 'file:' or a - * 'content:' URI. - * @param observer An observer callback to get notified when the package installation is - * complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be - * called when that happens. This parameter must not be null. + * @hide Install a package. Since this may take a little while, the result + * will be posted back to the given observer. An installation will + * fail if the calling context lacks the + * {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if + * the package named in the package file's manifest is already + * installed, or if there's no space available on the device. + * @param packageURI The location of the package file to install. This can + * be a 'file:' or a 'content:' URI. + * @param observer An observer callback to get notified when the package + * installation is complete. + * {@link IPackageInstallObserver#packageInstalled(String, int)} + * will be called when that happens. This parameter must not be + * null. * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, - * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. - * @param installerPackageName Optional package name of the application that is performing the - * installation. This identifies which market the package came from. - * @deprecated Use {@link #installPackage(Uri, IPackageInstallObserver2, int, String)} - * instead. This method will continue to be supported but the older observer interface - * will not get additional failure details. + * {@link #INSTALL_REPLACE_EXISTING}, + * {@link #INSTALL_ALLOW_TEST}. + * @param installerPackageName Optional package name of the application that + * is performing the installation. This identifies which market + * the package came from. + * @deprecated Use {@link #installPackage(Uri, PackageInstallObserver, int, + * String)} instead. This method will continue to be supported + * but the older observer interface will not get additional + * failure details. */ // @SystemApi public abstract void installPackage( @@ -2977,9 +2979,11 @@ public abstract class PackageManager { * @param observer An observer callback to get notified when the package * installation is complete. * {@link IPackageInstallObserver#packageInstalled(String, int)} - * will be called when that happens. This parameter must not be null. + * will be called when that happens. This parameter must not be + * null. * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, - * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * {@link #INSTALL_REPLACE_EXISTING}, + * {@link #INSTALL_ALLOW_TEST}. * @param installerPackageName Optional package name of the application that * is performing the installation. This identifies which market * the package came from. @@ -2992,10 +2996,11 @@ public abstract class PackageManager { * these parameters describing the encryption and authentication * used. May be {@code null}. * @hide - * @deprecated Use {@link #installPackageWithVerification(Uri, IPackageInstallObserver2, - * int, String, Uri, ManifestDigest, ContainerEncryptionParams)} instead. This method will - * continue to be supported but the older observer interface will not get additional failure - * details. + * @deprecated Use {@link #installPackageWithVerification(Uri, + * PackageInstallObserver, int, String, Uri, ManifestDigest, + * ContainerEncryptionParams)} instead. This method will + * continue to be supported but the older observer interface + * will not get additional failure details. */ // @SystemApi public abstract void installPackageWithVerification(Uri packageURI, @@ -3013,9 +3018,11 @@ public abstract class PackageManager { * @param observer An observer callback to get notified when the package * installation is complete. * {@link IPackageInstallObserver#packageInstalled(String, int)} - * will be called when that happens. This parameter must not be null. + * will be called when that happens. This parameter must not be + * null. * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, - * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * {@link #INSTALL_REPLACE_EXISTING}, + * {@link #INSTALL_ALLOW_TEST}. * @param installerPackageName Optional package name of the application that * is performing the installation. This identifies which market * the package came from. @@ -3024,12 +3031,12 @@ public abstract class PackageManager { * @param encryptionParams if the package to be installed is encrypted, * these parameters describing the encryption and authentication * used. May be {@code null}. - * * @hide * @deprecated Use {@link #installPackageWithVerificationAndEncryption(Uri, - * IPackageInstallObserver2, int, String, VerificationParams, - * ContainerEncryptionParams)} instead. This method will continue to be - * supported but the older observer interface will not get additional failure details. + * PackageInstallObserver, int, String, VerificationParams, + * ContainerEncryptionParams)} instead. This method will + * continue to be supported but the older observer interface + * will not get additional failure details. */ @Deprecated public abstract void installPackageWithVerificationAndEncryption(Uri packageURI, diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 682a38d..5f65a5e 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -24,12 +24,15 @@ import android.app.AppOpsManager; import android.content.Context; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstaller; +import android.content.pm.IPackageInstallerObserver; import android.content.pm.IPackageInstallerSession; -import android.content.pm.PackageInstallerParams; +import android.content.pm.InstallSessionInfo; +import android.content.pm.InstallSessionParams; import android.os.Binder; import android.os.FileUtils; import android.os.HandlerThread; import android.os.Process; +import android.os.RemoteException; import android.os.SELinux; import android.os.UserHandle; import android.os.UserManager; @@ -47,6 +50,8 @@ import com.google.android.collect.Sets; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; public class PackageInstallerService extends IPackageInstaller.Stub { private static final String TAG = "PackageInstaller"; @@ -138,7 +143,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public int createSession(String installerPackageName, PackageInstallerParams params, + public int createSession(String installerPackageName, InstallSessionParams params, int userId) { final int callingUid = Binder.getCallingUid(); mPm.enforceCrossUserPermission(callingUid, userId, false, TAG); @@ -217,29 +222,25 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public int[] getSessions(String installerPackageName, int userId) { - final int callingUid = Binder.getCallingUid(); - mPm.enforceCrossUserPermission(callingUid, userId, false, TAG); - mAppOps.checkPackage(callingUid, installerPackageName); + public List<InstallSessionInfo> getSessions(int userId) { + mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, false, TAG); - int[] matching = new int[0]; + final List<InstallSessionInfo> result = new ArrayList<>(); synchronized (mSessions) { for (int i = 0; i < mSessions.size(); i++) { - final int key = mSessions.keyAt(i); final PackageInstallerSession session = mSessions.valueAt(i); - if (session.userId == userId - && session.installerPackageName.equals(installerPackageName)) { - matching = ArrayUtils.appendInt(matching, key); + if (session.userId == userId) { + result.add(session.generateInfo()); } } } - return matching; + return result; } @Override - public void uninstall(String basePackageName, int flags, IPackageDeleteObserver observer, + public void uninstall(String packageName, int flags, IPackageDeleteObserver observer, int userId) { - mPm.deletePackageAsUser(basePackageName, observer, userId, flags); + mPm.deletePackageAsUser(packageName, observer, userId, flags); } @Override @@ -249,6 +250,16 @@ public class PackageInstallerService extends IPackageInstaller.Stub { throw new UnsupportedOperationException(); } + @Override + public void registerObserver(IPackageInstallerObserver observer, int userId) { + throw new UnsupportedOperationException(); + } + + @Override + public void unregisterObserver(IPackageInstallerObserver observer, int userId) { + throw new UnsupportedOperationException(); + } + class Callback { public void onProgressChanged(PackageInstallerSession session) { // TODO: notify listeners diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 3448803..6a7a0b2 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -26,7 +26,8 @@ import static android.system.OsConstants.O_WRONLY; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageInstallObserver2; import android.content.pm.IPackageInstallerSession; -import android.content.pm.PackageInstallerParams; +import android.content.pm.InstallSessionInfo; +import android.content.pm.InstallSessionParams; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.ApkLite; @@ -75,7 +76,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { public final String installerPackageName; /** UID not persisted */ public final int installerUid; - public final PackageInstallerParams params; + public final InstallSessionParams params; public final long createdMillis; public final File sessionStageDir; @@ -95,7 +96,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Slog.e(TAG, "Install failed: " + e); destroy(); try { - mRemoteObserver.packageInstalled(mPackageName, null, e.error); + mRemoteObserver.packageInstalled(mPackageName, null, e.error, + e.getMessage()); } catch (RemoteException ignored) { } } @@ -123,7 +125,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { public PackageInstallerSession(PackageInstallerService.Callback callback, PackageManagerService pm, int sessionId, int userId, String installerPackageName, - int installerUid, PackageInstallerParams params, long createdMillis, File sessionStageDir, + int installerUid, InstallSessionParams params, long createdMillis, File sessionStageDir, Looper looper) { mCallback = callback; mPm = pm; @@ -152,6 +154,21 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + public InstallSessionInfo generateInfo() { + final InstallSessionInfo info = new InstallSessionInfo(); + + info.sessionId = sessionId; + info.installerPackageName = installerPackageName; + info.progress = mProgress; + + info.fullInstall = params.fullInstall; + info.packageName = params.packageName; + info.icon = params.icon; + info.title = params.title; + + return info; + } + @Override public void updateProgress(int progress) { mProgress = progress; @@ -264,15 +281,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final IPackageInstallObserver2 remoteObserver = mRemoteObserver; final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() { @Override - public void packageInstalled(String basePackageName, Bundle extras, int returnCode) - throws RemoteException { + public void packageInstalled(String basePackageName, Bundle extras, int returnCode, + String msg) throws RemoteException { destroy(); - remoteObserver.packageInstalled(basePackageName, extras, returnCode); + remoteObserver.packageInstalled(basePackageName, extras, returnCode, msg); } }; - mPm.installStage(mPackageName, this.sessionStageDir, localObserver, params, installerPackageName, - installerUid, new UserHandle(userId)); + mPm.installStage(mPackageName, this.sessionStageDir, localObserver, params, + installerPackageName, installerUid, new UserHandle(userId)); } /** diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 1accfba..ca54679 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -91,12 +91,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.PackageInstallerParams; import android.content.pm.PackageManager; import android.content.pm.PackageParser.ActivityIntentInfo; import android.content.pm.PackageParser.PackageLite; @@ -1080,7 +1080,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (args.observer != null) { try { Bundle extras = extrasForInstallResult(res); - args.observer.packageInstalled(res.name, extras, res.returnCode); + args.observer.packageInstalled(res.name, extras, res.returnCode, null); } catch (RemoteException e) { Slog.i(TAG, "Observer no longer exists."); } @@ -7746,7 +7746,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (isUserRestricted(UserHandle.getUserId(uid), UserManager.DISALLOW_INSTALL_APPS)) { try { if (observer != null) { - observer.packageInstalled("", null, INSTALL_FAILED_USER_RESTRICTED); + observer.packageInstalled("", null, INSTALL_FAILED_USER_RESTRICTED, null); } } catch (RemoteException re) { } @@ -7779,7 +7779,7 @@ public class PackageManagerService extends IPackageManager.Stub { } void installStage(String packageName, File stageDir, IPackageInstallObserver2 observer, - PackageInstallerParams params, String installerPackageName, int installerUid, + InstallSessionParams params, String installerPackageName, int installerUid, UserHandle user) { final VerificationParams verifParams = new VerificationParams(null, params.originatingUri, params.referrerUri, installerUid, null); |