am 870e1f60: am 61c28588: am a1af0d42: Merge "PackageInstaller API refactoring." into lmp-dev
* commit '870e1f6039b00a4878a01c59e8b407571f6361ba': PackageInstaller API refactoring.
This commit is contained in:
106
api/current.txt
106
api/current.txt
@@ -8544,36 +8544,6 @@ package android.content.pm {
|
||||
field public int reqGlEsVersion;
|
||||
}
|
||||
|
||||
public class InstallSessionInfo implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public android.graphics.Bitmap getAppIcon();
|
||||
method public java.lang.CharSequence getAppLabel();
|
||||
method public java.lang.String getAppPackageName();
|
||||
method public android.content.Intent getDetailsIntent();
|
||||
method public java.lang.String getInstallerPackageName();
|
||||
method public float getProgress();
|
||||
method public int getSessionId();
|
||||
method public boolean isOpen();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
}
|
||||
|
||||
public class InstallSessionParams implements android.os.Parcelable {
|
||||
ctor public InstallSessionParams(int);
|
||||
method public int describeContents();
|
||||
method public void setAppIcon(android.graphics.Bitmap);
|
||||
method public void setAppLabel(java.lang.CharSequence);
|
||||
method public void setAppPackageName(java.lang.String);
|
||||
method public void setInstallLocation(int);
|
||||
method public void setOriginatingUri(android.net.Uri);
|
||||
method public void setReferrerUri(android.net.Uri);
|
||||
method public void setSize(long);
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
field public static final int MODE_FULL_INSTALL = 1; // 0x1
|
||||
field public static final int MODE_INHERIT_EXISTING = 2; // 0x2
|
||||
}
|
||||
|
||||
public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
|
||||
ctor public InstrumentationInfo();
|
||||
ctor public InstrumentationInfo(android.content.pm.InstrumentationInfo);
|
||||
@@ -8675,37 +8645,35 @@ package android.content.pm {
|
||||
public class PackageInstaller {
|
||||
method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
|
||||
method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler);
|
||||
method public int createSession(android.content.pm.InstallSessionParams) throws java.io.IOException;
|
||||
method public java.util.List<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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -16,4 +16,5 @@
|
||||
|
||||
package android.content.pm;
|
||||
|
||||
parcelable InstallSessionInfo;
|
||||
parcelable PackageInstaller.SessionParams;
|
||||
parcelable PackageInstaller.SessionInfo;
|
||||
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user