am 870e1f60: am 61c28588: am a1af0d42: Merge "PackageInstaller API refactoring." into lmp-dev

* commit '870e1f6039b00a4878a01c59e8b407571f6361ba':
  PackageInstaller API refactoring.
This commit is contained in:
Jeff Sharkey
2014-08-16 00:44:50 +00:00
committed by Android Git Automerger
16 changed files with 767 additions and 867 deletions

View File

@@ -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<android.content.pm.InstallSessionInfo> getAllSessions();
method public java.util.List<android.content.pm.InstallSessionInfo> 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<android.content.pm.PackageInstaller.SessionInfo> getAllSessions();
method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> 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 {

View File

@@ -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<Intent> 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;

View File

@@ -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();

View File

@@ -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<InstallSessionInfo> getAllSessions(int userId);
List<InstallSessionInfo> getMySessions(String installerPackageName, int userId);
PackageInstaller.SessionInfo getSessionInfo(int sessionId);
List<PackageInstaller.SessionInfo> getAllSessions(int userId);
List<PackageInstaller.SessionInfo> 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);
}

View File

@@ -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();
}

View File

@@ -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.
* <p>
* 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.
* <p>
* 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<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];
}
};
}

View File

@@ -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;

View File

@@ -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.
* <p>
* 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.
* <p>
* 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<InstallSessionParams>
CREATOR = new Parcelable.Creator<InstallSessionParams>() {
@Override
public InstallSessionParams createFromParcel(Parcel p) {
return new InstallSessionParams(p);
}
@Override
public InstallSessionParams[] newArray(int size) {
return new InstallSessionParams[size];
}
};
}

View File

@@ -16,4 +16,5 @@
package android.content.pm;
parcelable InstallSessionInfo;
parcelable PackageInstaller.SessionParams;
parcelable PackageInstaller.SessionInfo;

View File

@@ -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;
* </ul>
*/
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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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<SessionCallbackDelegate> 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<InstallSessionInfo> getAllSessions() {
public @NonNull List<SessionInfo> 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<InstallSessionInfo> getMySessions() {
public @NonNull List<SessionInfo> 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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<SessionParams>
CREATOR = new Parcelable.Creator<SessionParams>() {
@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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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<SessionInfo>
CREATOR = new Parcelable.Creator<SessionInfo>() {
@Override
public SessionInfo createFromParcel(Parcel p) {
return new SessionInfo(p);
}
@Override
public SessionInfo[] newArray(int size) {
return new SessionInfo[size];
}
};
}
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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<InstallSessionInfo> getAllSessions(int userId) {
public List<SessionInfo> getAllSessions(int userId) {
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getAllSessions");
enforceCallerCanReadSessions();
final List<InstallSessionInfo> result = new ArrayList<>();
final List<SessionInfo> 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<InstallSessionInfo> getMySessions(String installerPackageName, int userId) {
public List<SessionInfo> getMySessions(String installerPackageName, int userId) {
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getMySessions");
mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
final List<InstallSessionInfo> result = new ArrayList<>();
final List<SessionInfo> 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;

View File

@@ -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,

View File

@@ -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);