Merge "Installing splits into ASECs!" into lmp-dev
This commit is contained in:
@ -8675,10 +8675,12 @@ package android.content.pm {
|
||||
method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
|
||||
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_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
|
||||
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
|
||||
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
|
||||
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 java.lang.String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH";
|
||||
field public static final int STATUS_FAILURE = 1; // 0x1
|
||||
field public static final int STATUS_FAILURE_ABORTED = 3; // 0x3
|
||||
field public static final int STATUS_FAILURE_BLOCKED = 2; // 0x2
|
||||
|
@ -1004,6 +1004,10 @@ public final class Pm {
|
||||
params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
|
||||
} else if (opt.equals("-p")) {
|
||||
params.mode = SessionParams.MODE_INHERIT_EXISTING;
|
||||
params.appPackageName = nextOptionData();
|
||||
if (params.appPackageName == null) {
|
||||
throw new IllegalArgumentException("Missing inherit package name");
|
||||
}
|
||||
} else if (opt.equals("-S")) {
|
||||
params.setSize(Long.parseLong(nextOptionData()));
|
||||
} else if (opt.equals("--abi")) {
|
||||
|
@ -45,6 +45,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@ -86,6 +87,8 @@ public class PackageInstaller {
|
||||
* <p>
|
||||
* In some cases, a matching Activity may not exist, so ensure you safeguard
|
||||
* against this.
|
||||
* <p>
|
||||
* The session to show details for is defined in {@link #EXTRA_SESSION_ID}.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
|
||||
public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
|
||||
@ -95,22 +98,58 @@ public class PackageInstaller {
|
||||
ACTION_CONFIRM_PERMISSIONS = "android.content.pm.action.CONFIRM_PERMISSIONS";
|
||||
|
||||
/**
|
||||
* An integer session ID.
|
||||
* An integer session ID that an operation is working with.
|
||||
*
|
||||
* @see #ACTION_SESSION_DETAILS
|
||||
* @see Intent#getIntExtra(String, int)
|
||||
*/
|
||||
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";
|
||||
|
||||
/**
|
||||
* Package name relevant to a status.
|
||||
* Package name that an operation is working with.
|
||||
*
|
||||
* @see Intent#getStringExtra(String)
|
||||
*/
|
||||
public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
|
||||
|
||||
/**
|
||||
* Current status of an operation. Will be one of
|
||||
* {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS},
|
||||
* {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED},
|
||||
* {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT},
|
||||
* {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or
|
||||
* {@link #STATUS_FAILURE_STORAGE}.
|
||||
* <p>
|
||||
* More information about a status may be available through additional
|
||||
* extras; see the individual status documentation for details.
|
||||
*
|
||||
* @see Intent#getIntExtra(String, int)
|
||||
*/
|
||||
public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS";
|
||||
|
||||
/**
|
||||
* Detailed string representation of the status, including raw details that
|
||||
* are useful for debugging.
|
||||
*
|
||||
* @see Intent#getStringExtra(String)
|
||||
*/
|
||||
public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
|
||||
|
||||
/**
|
||||
* Another package name relevant to a status. This is typically the package
|
||||
* responsible for causing an operation failure.
|
||||
*
|
||||
* @see Intent#getStringExtra(String)
|
||||
*/
|
||||
public static final String
|
||||
EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
|
||||
|
||||
/**
|
||||
* Storage path relevant to a status.
|
||||
*
|
||||
* @see Intent#getStringExtra(String)
|
||||
*/
|
||||
public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH";
|
||||
|
||||
/** {@hide} */
|
||||
@Deprecated
|
||||
public static final String EXTRA_PACKAGE_NAMES = "android.content.pm.extra.PACKAGE_NAMES";
|
||||
@ -153,8 +192,12 @@ public class PackageInstaller {
|
||||
* 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.
|
||||
* <p>
|
||||
* The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
|
||||
* specific package blocking the install.
|
||||
*
|
||||
* @see #EXTRA_STATUS_MESSAGE
|
||||
* @see #EXTRA_OTHER_PACKAGE_NAME
|
||||
*/
|
||||
public static final int STATUS_FAILURE_BLOCKED = 2;
|
||||
|
||||
@ -182,10 +225,11 @@ public class PackageInstaller {
|
||||
* 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_NAME} with the
|
||||
* The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
|
||||
* specific package identified as the cause of the conflict.
|
||||
*
|
||||
* @see #EXTRA_STATUS_MESSAGE
|
||||
* @see #EXTRA_OTHER_PACKAGE_NAME
|
||||
*/
|
||||
public static final int STATUS_FAILURE_CONFLICT = 5;
|
||||
|
||||
@ -193,8 +237,12 @@ public class PackageInstaller {
|
||||
* 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.
|
||||
* <p>
|
||||
* The result may also contain {@link #EXTRA_STORAGE_PATH} with the path to
|
||||
* the storage device that caused the failure.
|
||||
*
|
||||
* @see #EXTRA_STATUS_MESSAGE
|
||||
* @see #EXTRA_STORAGE_PATH
|
||||
*/
|
||||
public static final int STATUS_FAILURE_STORAGE = 6;
|
||||
|
||||
@ -281,6 +329,13 @@ public class PackageInstaller {
|
||||
* To succeed, the caller must be the current home app.
|
||||
*/
|
||||
public @NonNull List<SessionInfo> getAllSessions() {
|
||||
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 Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
try {
|
||||
return mInstaller.getAllSessions(mUserId);
|
||||
} catch (RemoteException e) {
|
||||
|
@ -264,7 +264,7 @@ public class PackageParser {
|
||||
public final boolean coreApp;
|
||||
public final boolean multiArch;
|
||||
|
||||
private PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
|
||||
public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
|
||||
String[] splitCodePaths) {
|
||||
this.packageName = baseApk.packageName;
|
||||
this.versionCode = baseApk.versionCode;
|
||||
|
@ -321,7 +321,7 @@ public interface IMountService extends IInterface {
|
||||
* Mount a secure container with the specified key and owner UID.
|
||||
* Returns an int consistent with MountServiceResultCode
|
||||
*/
|
||||
public int mountSecureContainer(String id, String key, int ownerUid)
|
||||
public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly)
|
||||
throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
@ -331,6 +331,7 @@ public interface IMountService extends IInterface {
|
||||
_data.writeString(id);
|
||||
_data.writeString(key);
|
||||
_data.writeInt(ownerUid);
|
||||
_data.writeInt(readOnly ? 1 : 0);
|
||||
mRemote.transact(Stub.TRANSACTION_mountSecureContainer, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
@ -834,6 +835,27 @@ public interface IMountService extends IInterface {
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int resizeSecureContainer(String id, int sizeMb, String key)
|
||||
throws RemoteException {
|
||||
Parcel _data = Parcel.obtain();
|
||||
Parcel _reply = Parcel.obtain();
|
||||
int _result;
|
||||
try {
|
||||
_data.writeInterfaceToken(DESCRIPTOR);
|
||||
_data.writeString(id);
|
||||
_data.writeInt(sizeMb);
|
||||
_data.writeString(key);
|
||||
mRemote.transact(Stub.TRANSACTION_resizeSecureContainer, _data, _reply, 0);
|
||||
_reply.readException();
|
||||
_result = _reply.readInt();
|
||||
} finally {
|
||||
_reply.recycle();
|
||||
_data.recycle();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String DESCRIPTOR = "IMountService";
|
||||
@ -918,6 +940,8 @@ public interface IMountService extends IInterface {
|
||||
|
||||
static final int TRANSACTION_getField = IBinder.FIRST_CALL_TRANSACTION + 39;
|
||||
|
||||
static final int TRANSACTION_resizeSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 40;
|
||||
|
||||
/**
|
||||
* Cast an IBinder object into an IMountService interface, generating a
|
||||
* proxy if needed.
|
||||
@ -1082,7 +1106,9 @@ public interface IMountService extends IInterface {
|
||||
key = data.readString();
|
||||
int ownerUid;
|
||||
ownerUid = data.readInt();
|
||||
int resultCode = mountSecureContainer(id, key, ownerUid);
|
||||
boolean readOnly;
|
||||
readOnly = data.readInt() != 0;
|
||||
int resultCode = mountSecureContainer(id, key, ownerUid, readOnly);
|
||||
reply.writeNoException();
|
||||
reply.writeInt(resultCode);
|
||||
return true;
|
||||
@ -1308,6 +1334,19 @@ public interface IMountService extends IInterface {
|
||||
reply.writeString(contents);
|
||||
return true;
|
||||
}
|
||||
case TRANSACTION_resizeSecureContainer: {
|
||||
data.enforceInterface(DESCRIPTOR);
|
||||
String id;
|
||||
id = data.readString();
|
||||
int sizeMb;
|
||||
sizeMb = data.readInt();
|
||||
String key;
|
||||
key = data.readString();
|
||||
int resultCode = resizeSecureContainer(id, sizeMb, key);
|
||||
reply.writeNoException();
|
||||
reply.writeInt(resultCode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onTransact(code, data, reply, flags);
|
||||
}
|
||||
@ -1405,7 +1444,8 @@ public interface IMountService extends IInterface {
|
||||
* Mount a secure container with the specified key and owner UID. Returns an
|
||||
* int consistent with MountServiceResultCode
|
||||
*/
|
||||
public int mountSecureContainer(String id, String key, int ownerUid) throws RemoteException;
|
||||
public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly)
|
||||
throws RemoteException;
|
||||
|
||||
/**
|
||||
* Mount external storage at given mount point. Returns an int consistent
|
||||
@ -1571,4 +1611,6 @@ public interface IMountService extends IInterface {
|
||||
* @return contents of field
|
||||
*/
|
||||
public String getField(String field) throws RemoteException;
|
||||
|
||||
public int resizeSecureContainer(String id, int sizeMb, String key) throws RemoteException;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import static android.system.OsConstants.S_IRWXU;
|
||||
import static android.system.OsConstants.S_IXGRP;
|
||||
import static android.system.OsConstants.S_IXOTH;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageParser.Package;
|
||||
@ -51,9 +52,11 @@ import java.util.List;
|
||||
*/
|
||||
public class NativeLibraryHelper {
|
||||
private static final String TAG = "NativeHelper";
|
||||
|
||||
private static final boolean DEBUG_NATIVE = false;
|
||||
|
||||
public static final String LIB_DIR_NAME = "lib";
|
||||
public static final String LIB64_DIR_NAME = "lib64";
|
||||
|
||||
// Special value for {@code PackageParser.Package#cpuAbiOverride} to indicate
|
||||
// that the cpuAbiOverride must be clear.
|
||||
public static final String CLEAR_ABI_OVERRIDE = "-";
|
||||
@ -70,6 +73,7 @@ public class NativeLibraryHelper {
|
||||
private volatile boolean mClosed;
|
||||
|
||||
final long[] apkHandles;
|
||||
final boolean multiArch;
|
||||
|
||||
public static Handle create(File packageFile) throws IOException {
|
||||
try {
|
||||
@ -81,14 +85,15 @@ public class NativeLibraryHelper {
|
||||
}
|
||||
|
||||
public static Handle create(Package pkg) throws IOException {
|
||||
return create(pkg.getAllCodePaths());
|
||||
return create(pkg.getAllCodePaths(),
|
||||
(pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0);
|
||||
}
|
||||
|
||||
public static Handle create(PackageLite lite) throws IOException {
|
||||
return create(lite.getAllCodePaths());
|
||||
return create(lite.getAllCodePaths(), lite.multiArch);
|
||||
}
|
||||
|
||||
private static Handle create(List<String> codePaths) throws IOException {
|
||||
private static Handle create(List<String> codePaths, boolean multiArch) throws IOException {
|
||||
final int size = codePaths.size();
|
||||
final long[] apkHandles = new long[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
@ -103,11 +108,12 @@ public class NativeLibraryHelper {
|
||||
}
|
||||
}
|
||||
|
||||
return new Handle(apkHandles);
|
||||
return new Handle(apkHandles, multiArch);
|
||||
}
|
||||
|
||||
Handle(long[] apkHandles) {
|
||||
Handle(long[] apkHandles, boolean multiArch) {
|
||||
this.apkHandles = apkHandles;
|
||||
this.multiArch = multiArch;
|
||||
mGuard.open("close");
|
||||
}
|
||||
|
||||
@ -159,8 +165,7 @@ public class NativeLibraryHelper {
|
||||
* @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another
|
||||
* error code from that class if not
|
||||
*/
|
||||
public static int copyNativeBinariesIfNeededLI(Handle handle, File sharedLibraryDir,
|
||||
String abi) {
|
||||
public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) {
|
||||
for (long apkHandle : handle.apkHandles) {
|
||||
int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi);
|
||||
if (res != INSTALL_SUCCEEDED) {
|
||||
@ -267,7 +272,7 @@ public class NativeLibraryHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private static long sumNativeBinaries(Handle handle, String[] abiList) {
|
||||
private static long sumNativeBinariesForSupportedAbi(Handle handle, String[] abiList) {
|
||||
int abi = findSupportedAbi(handle, abiList);
|
||||
if (abi >= 0) {
|
||||
return sumNativeBinaries(handle, abiList[abi]);
|
||||
@ -276,7 +281,7 @@ public class NativeLibraryHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static int copyNativeBinariesIfNeededLI(Handle handle, File libraryRoot,
|
||||
public static int copyNativeBinariesForSupportedAbi(Handle handle, File libraryRoot,
|
||||
String[] abiList, boolean useIsaSubdir) throws IOException {
|
||||
createNativeLibrarySubdir(libraryRoot);
|
||||
|
||||
@ -300,7 +305,7 @@ public class NativeLibraryHelper {
|
||||
subDir = libraryRoot;
|
||||
}
|
||||
|
||||
int copyRet = copyNativeBinariesIfNeededLI(handle, subDir, abiList[abi]);
|
||||
int copyRet = copyNativeBinaries(handle, subDir, abiList[abi]);
|
||||
if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
|
||||
return copyRet;
|
||||
}
|
||||
@ -309,10 +314,10 @@ public class NativeLibraryHelper {
|
||||
return abi;
|
||||
}
|
||||
|
||||
public static int copyNativeBinariesIfNeededLI(Handle handle, File libraryRoot,
|
||||
String abiOverride, boolean multiArch) {
|
||||
public static int copyNativeBinariesWithOverride(Handle handle, File libraryRoot,
|
||||
String abiOverride) {
|
||||
try {
|
||||
if (multiArch) {
|
||||
if (handle.multiArch) {
|
||||
// Warn if we've set an abiOverride for multi-lib packages..
|
||||
// By definition, we need to copy both 32 and 64 bit libraries for
|
||||
// such packages.
|
||||
@ -322,7 +327,7 @@ public class NativeLibraryHelper {
|
||||
|
||||
int copyRet = PackageManager.NO_NATIVE_LIBRARIES;
|
||||
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
|
||||
copyRet = copyNativeBinariesIfNeededLI(handle, libraryRoot,
|
||||
copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot,
|
||||
Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */);
|
||||
if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
|
||||
copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
|
||||
@ -332,7 +337,7 @@ public class NativeLibraryHelper {
|
||||
}
|
||||
|
||||
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
|
||||
copyRet = copyNativeBinariesIfNeededLI(handle, libraryRoot,
|
||||
copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot,
|
||||
Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */);
|
||||
if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
|
||||
copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
|
||||
@ -355,7 +360,7 @@ public class NativeLibraryHelper {
|
||||
abiList = Build.SUPPORTED_32_BIT_ABIS;
|
||||
}
|
||||
|
||||
int copyRet = copyNativeBinariesIfNeededLI(handle, libraryRoot, abiList,
|
||||
int copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, abiList,
|
||||
true /* use isa specific subdirs */);
|
||||
if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
|
||||
Slog.w(TAG, "Failure copying native libraries [errorCode=" + copyRet + "]");
|
||||
@ -370,10 +375,10 @@ public class NativeLibraryHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static long sumNativeBinaries(Handle handle, String abiOverride, boolean multiArch)
|
||||
public static long sumNativeBinariesWithOverride(Handle handle, String abiOverride)
|
||||
throws IOException {
|
||||
long sum = 0;
|
||||
if (multiArch) {
|
||||
if (handle.multiArch) {
|
||||
// Warn if we've set an abiOverride for multi-lib packages..
|
||||
// By definition, we need to copy both 32 and 64 bit libraries for
|
||||
// such packages.
|
||||
@ -382,11 +387,11 @@ public class NativeLibraryHelper {
|
||||
}
|
||||
|
||||
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
|
||||
sum += sumNativeBinaries(handle, Build.SUPPORTED_32_BIT_ABIS);
|
||||
sum += sumNativeBinariesForSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
|
||||
}
|
||||
|
||||
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
|
||||
sum += sumNativeBinaries(handle, Build.SUPPORTED_64_BIT_ABIS);
|
||||
sum += sumNativeBinariesForSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
|
||||
}
|
||||
} else {
|
||||
String cpuAbiOverride = null;
|
||||
@ -403,7 +408,7 @@ public class NativeLibraryHelper {
|
||||
abiList = Build.SUPPORTED_32_BIT_ABIS;
|
||||
}
|
||||
|
||||
sum += sumNativeBinaries(handle, abiList);
|
||||
sum += sumNativeBinariesForSupportedAbi(handle, abiList);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
@ -16,11 +16,14 @@
|
||||
|
||||
package com.android.internal.content;
|
||||
|
||||
import static android.net.TrafficStats.MB_IN_BYTES;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.PackageParser.PackageLite;
|
||||
import android.os.Environment;
|
||||
import android.os.Environment.UserEnvironment;
|
||||
import android.os.FileUtils;
|
||||
@ -77,9 +80,10 @@ public class PackageHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static String createSdDir(int sizeMb, String cid, String sdEncKey, int uid,
|
||||
public static String createSdDir(long sizeBytes, String cid, String sdEncKey, int uid,
|
||||
boolean isExternal) {
|
||||
// Create mount point via MountService
|
||||
// Round up to nearest MB, plus another MB for filesystem overhead
|
||||
final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1;
|
||||
try {
|
||||
IMountService mountService = getMountService();
|
||||
|
||||
@ -102,19 +106,39 @@ public class PackageHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String mountSdDir(String cid, String key, int ownerUid) {
|
||||
try {
|
||||
int rc = getMountService().mountSecureContainer(cid, key, ownerUid);
|
||||
if (rc != StorageResultCode.OperationSucceeded) {
|
||||
Log.i(TAG, "Failed to mount container " + cid + " rc : " + rc);
|
||||
return null;
|
||||
public static boolean resizeSdDir(long sizeBytes, String cid, String sdEncKey) {
|
||||
// Round up to nearest MB, plus another MB for filesystem overhead
|
||||
final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1;
|
||||
try {
|
||||
IMountService mountService = getMountService();
|
||||
int rc = mountService.resizeSecureContainer(cid, sizeMb, sdEncKey);
|
||||
if (rc == StorageResultCode.OperationSucceeded) {
|
||||
return true;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "MountService running?");
|
||||
}
|
||||
return getMountService().getSecureContainerPath(cid);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "MountService running?");
|
||||
Log.e(TAG, "Failed to create secure container " + cid);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String mountSdDir(String cid, String key, int ownerUid) {
|
||||
return mountSdDir(cid, key, ownerUid, true);
|
||||
}
|
||||
|
||||
public static String mountSdDir(String cid, String key, int ownerUid, boolean readOnly) {
|
||||
try {
|
||||
int rc = getMountService().mountSecureContainer(cid, key, ownerUid, readOnly);
|
||||
if (rc != StorageResultCode.OperationSucceeded) {
|
||||
Log.i(TAG, "Failed to mount container " + cid + " rc : " + rc);
|
||||
return null;
|
||||
}
|
||||
return getMountService().getSecureContainerPath(cid);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "MountService running?");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean unMountSdDir(String cid) {
|
||||
try {
|
||||
@ -400,6 +424,37 @@ public class PackageHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static long calculateInstalledSize(PackageLite pkg, boolean isForwardLocked,
|
||||
String abiOverride) throws IOException {
|
||||
NativeLibraryHelper.Handle handle = null;
|
||||
try {
|
||||
handle = NativeLibraryHelper.Handle.create(pkg);
|
||||
return calculateInstalledSize(pkg, handle, isForwardLocked, abiOverride);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(handle);
|
||||
}
|
||||
}
|
||||
|
||||
public static long calculateInstalledSize(PackageLite pkg, NativeLibraryHelper.Handle handle,
|
||||
boolean isForwardLocked, String abiOverride) throws IOException {
|
||||
long sizeBytes = 0;
|
||||
|
||||
// Include raw APKs, and possibly unpacked resources
|
||||
for (String codePath : pkg.getAllCodePaths()) {
|
||||
final File codeFile = new File(codePath);
|
||||
sizeBytes += codeFile.length();
|
||||
|
||||
if (isForwardLocked) {
|
||||
sizeBytes += PackageHelper.extractPublicFiles(codeFile, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Include all relevant native code
|
||||
sizeBytes += NativeLibraryHelper.sumNativeBinariesWithOverride(handle, abiOverride);
|
||||
|
||||
return sizeBytes;
|
||||
}
|
||||
|
||||
public static String replaceEnd(String str, String before, String after) {
|
||||
if (!str.endsWith(before)) {
|
||||
throw new IllegalArgumentException(
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
package android.content.pm;
|
||||
|
||||
import com.android.internal.content.PackageHelper;
|
||||
import static android.net.TrafficStats.MB_IN_BYTES;
|
||||
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
@ -25,6 +25,8 @@ import android.os.storage.IMountService;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.content.PackageHelper;
|
||||
|
||||
public class PackageHelperTests extends AndroidTestCase {
|
||||
private static final boolean localLOGV = true;
|
||||
public static final String TAG = "PackageHelperTests";
|
||||
@ -81,8 +83,8 @@ public class PackageHelperTests extends AndroidTestCase {
|
||||
public void testMountAndPullSdCard() {
|
||||
try {
|
||||
fullId = PREFIX;
|
||||
fullId2 = PackageHelper.createSdDir(1024, fullId, "none", android.os.Process.myUid(),
|
||||
true);
|
||||
fullId2 = PackageHelper.createSdDir(1024 * MB_IN_BYTES, fullId, "none",
|
||||
android.os.Process.myUid(), true);
|
||||
|
||||
Log.d(TAG,PackageHelper.getSdDir(fullId));
|
||||
PackageHelper.unMountSdDir(fullId);
|
||||
|
@ -90,7 +90,7 @@ public class AsecTests extends AndroidTestCase {
|
||||
String fullId = SECURE_CONTAINER_PREFIX + localId;
|
||||
|
||||
IMountService ms = getMs();
|
||||
return ms.mountSecureContainer(fullId, key, android.os.Process.myUid());
|
||||
return ms.mountSecureContainer(fullId, key, android.os.Process.myUid(), true);
|
||||
}
|
||||
|
||||
private int renameContainer(String localId1, String localId2) throws Exception {
|
||||
|
@ -295,6 +295,8 @@ public:
|
||||
data.writeString16(id);
|
||||
data.writeString16(key);
|
||||
data.writeInt32(ownerUid);
|
||||
// Assume read-only
|
||||
data.writeInt32(1);
|
||||
if (remote()->transact(TRANSACTION_mountSecureContainer, data, &reply) != NO_ERROR) {
|
||||
ALOGD("mountSecureContainer couldn't call remote");
|
||||
return -1;
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.defcontainer;
|
||||
|
||||
import static android.net.TrafficStats.MB_IN_BYTES;
|
||||
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.content.Context;
|
||||
@ -67,8 +67,6 @@ import java.io.OutputStream;
|
||||
public class DefaultContainerService extends IntentService {
|
||||
private static final String TAG = "DefContainer";
|
||||
|
||||
private static final String LIB_DIR_NAME = "lib";
|
||||
|
||||
// TODO: migrate native code unpacking to always be a derivative work
|
||||
|
||||
private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() {
|
||||
@ -168,7 +166,7 @@ public class DefaultContainerService extends IntentService {
|
||||
final long sizeBytes;
|
||||
try {
|
||||
pkg = PackageParser.parsePackageLite(packageFile, 0);
|
||||
sizeBytes = calculateInstalledSizeInner(pkg, isForwardLocked, abiOverride);
|
||||
sizeBytes = PackageHelper.calculateInstalledSize(pkg, isForwardLocked, abiOverride);
|
||||
} catch (PackageParserException | IOException e) {
|
||||
Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
|
||||
|
||||
@ -253,7 +251,7 @@ public class DefaultContainerService extends IntentService {
|
||||
final PackageParser.PackageLite pkg;
|
||||
try {
|
||||
pkg = PackageParser.parsePackageLite(packageFile, 0);
|
||||
return calculateInstalledSizeInner(pkg, isForwardLocked, abiOverride);
|
||||
return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, abiOverride);
|
||||
} catch (PackageParserException | IOException e) {
|
||||
Slog.w(TAG, "Failed to calculate installed size: " + e);
|
||||
return Long.MAX_VALUE;
|
||||
@ -315,13 +313,12 @@ public class DefaultContainerService extends IntentService {
|
||||
|
||||
// Calculate container size, rounding up to nearest MB and adding an
|
||||
// extra MB for filesystem overhead
|
||||
final long sizeBytes = calculateInstalledSizeInner(pkg, handle, isForwardLocked,
|
||||
abiOverride);
|
||||
final int sizeMb = ((int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES)) + 1;
|
||||
final long sizeBytes = PackageHelper.calculateInstalledSize(pkg, handle,
|
||||
isForwardLocked, abiOverride);
|
||||
|
||||
// Create new container
|
||||
final String newMountPath = PackageHelper.createSdDir(sizeMb, newCid, key, Process.myUid(),
|
||||
isExternal);
|
||||
final String newMountPath = PackageHelper.createSdDir(sizeBytes, newCid, key,
|
||||
Process.myUid(), isExternal);
|
||||
if (newMountPath == null) {
|
||||
throw new IOException("Failed to create container " + newCid);
|
||||
}
|
||||
@ -339,8 +336,8 @@ public class DefaultContainerService extends IntentService {
|
||||
|
||||
// Extract native code
|
||||
final File libraryRoot = new File(targetDir, LIB_DIR_NAME);
|
||||
final int res = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, libraryRoot,
|
||||
abiOverride, pkg.multiArch);
|
||||
final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
|
||||
abiOverride);
|
||||
if (res != PackageManager.INSTALL_SUCCEEDED) {
|
||||
throw new IOException("Failed to extract native code, res=" + res);
|
||||
}
|
||||
@ -415,35 +412,4 @@ public class DefaultContainerService extends IntentService {
|
||||
Os.chmod(targetFile.getAbsolutePath(), 0644);
|
||||
}
|
||||
}
|
||||
|
||||
private long calculateInstalledSizeInner(PackageLite pkg, boolean isForwardLocked,
|
||||
String abiOverride) throws IOException {
|
||||
NativeLibraryHelper.Handle handle = null;
|
||||
try {
|
||||
handle = NativeLibraryHelper.Handle.create(pkg);
|
||||
return calculateInstalledSizeInner(pkg, handle, isForwardLocked, abiOverride);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(handle);
|
||||
}
|
||||
}
|
||||
|
||||
private long calculateInstalledSizeInner(PackageLite pkg, NativeLibraryHelper.Handle handle,
|
||||
boolean isForwardLocked, String abiOverride) throws IOException {
|
||||
long sizeBytes = 0;
|
||||
|
||||
// Include raw APKs, and possibly unpacked resources
|
||||
for (String codePath : pkg.getAllCodePaths()) {
|
||||
final File codeFile = new File(codePath);
|
||||
sizeBytes += codeFile.length();
|
||||
|
||||
if (isForwardLocked) {
|
||||
sizeBytes += PackageHelper.extractPublicFiles(codeFile, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Include all relevant native code
|
||||
sizeBytes += NativeLibraryHelper.sumNativeBinaries(handle, abiOverride, pkg.multiArch);
|
||||
|
||||
return sizeBytes;
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Environment;
|
||||
@ -1761,6 +1760,21 @@ class MountService extends IMountService.Stub
|
||||
return rc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int resizeSecureContainer(String id, int sizeMb, String key) {
|
||||
validatePermission(android.Manifest.permission.ASEC_CREATE);
|
||||
waitForReady();
|
||||
warnOnNotMounted();
|
||||
|
||||
int rc = StorageResultCode.OperationSucceeded;
|
||||
try {
|
||||
mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
|
||||
} catch (NativeDaemonConnectorException e) {
|
||||
rc = StorageResultCode.OperationFailedInternalError;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
public int finalizeSecureContainer(String id) {
|
||||
validatePermission(android.Manifest.permission.ASEC_CREATE);
|
||||
warnOnNotMounted();
|
||||
@ -1835,7 +1849,7 @@ class MountService extends IMountService.Stub
|
||||
return rc;
|
||||
}
|
||||
|
||||
public int mountSecureContainer(String id, String key, int ownerUid) {
|
||||
public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
|
||||
validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
|
||||
waitForReady();
|
||||
warnOnNotMounted();
|
||||
@ -1848,7 +1862,8 @@ class MountService extends IMountService.Stub
|
||||
|
||||
int rc = StorageResultCode.OperationSucceeded;
|
||||
try {
|
||||
mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid);
|
||||
mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
|
||||
readOnly ? "ro" : "rw");
|
||||
} catch (NativeDaemonConnectorException e) {
|
||||
int code = e.getCode();
|
||||
if (code != VoldResponseCode.OpFailedStorageBusy) {
|
||||
|
@ -19,7 +19,6 @@ package com.android.server.pm;
|
||||
import static android.content.pm.PackageManager.INSTALL_ALL_USERS;
|
||||
import static android.content.pm.PackageManager.INSTALL_FROM_ADB;
|
||||
import static android.content.pm.PackageManager.INSTALL_REPLACE_EXISTING;
|
||||
import static android.net.TrafficStats.MB_IN_BYTES;
|
||||
import static com.android.internal.util.XmlUtils.readBitmapAttribute;
|
||||
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
|
||||
import static com.android.internal.util.XmlUtils.readIntAttribute;
|
||||
@ -48,8 +47,11 @@ import android.content.pm.IPackageInstaller;
|
||||
import android.content.pm.IPackageInstallerCallback;
|
||||
import android.content.pm.IPackageInstallerSession;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageInstaller.SessionInfo;
|
||||
import android.content.pm.PackageInstaller.SessionParams;
|
||||
import android.content.pm.PackageParser.PackageLite;
|
||||
import android.content.pm.PackageParser.PackageParserException;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
@ -208,7 +210,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
// Ignore stages claimed by active sessions
|
||||
for (int i = 0; i < mSessions.size(); i++) {
|
||||
final PackageInstallerSession session = mSessions.valueAt(i);
|
||||
unclaimed.remove(session.internalStageDir);
|
||||
unclaimed.remove(session.stageDir);
|
||||
}
|
||||
|
||||
// Clean up orphaned staging directories
|
||||
@ -234,7 +236,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
// Ignore stages claimed by active sessions
|
||||
for (int i = 0; i < mSessions.size(); i++) {
|
||||
final PackageInstallerSession session = mSessions.valueAt(i);
|
||||
final String cid = session.externalStageCid;
|
||||
final String cid = session.stageCid;
|
||||
|
||||
if (unclaimed.remove(cid)) {
|
||||
// Claimed by active session, mount it
|
||||
@ -304,10 +306,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
Slog.w(TAG, "Abandoning old session first created at "
|
||||
+ session.createdMillis);
|
||||
valid = false;
|
||||
} else if (session.internalStageDir != null
|
||||
&& !session.internalStageDir.exists()) {
|
||||
} else if (session.stageDir != null
|
||||
&& !session.stageDir.exists()) {
|
||||
Slog.w(TAG, "Abandoning internal session with missing stage "
|
||||
+ session.internalStageDir);
|
||||
+ session.stageDir);
|
||||
valid = false;
|
||||
} else {
|
||||
valid = true;
|
||||
@ -401,12 +403,12 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
|
||||
session.installerPackageName);
|
||||
writeLongAttribute(out, ATTR_CREATED_MILLIS, session.createdMillis);
|
||||
if (session.internalStageDir != null) {
|
||||
if (session.stageDir != null) {
|
||||
writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
|
||||
session.internalStageDir.getAbsolutePath());
|
||||
session.stageDir.getAbsolutePath());
|
||||
}
|
||||
if (session.externalStageCid != null) {
|
||||
writeStringAttribute(out, ATTR_SESSION_STAGE_CID, session.externalStageCid);
|
||||
if (session.stageCid != null) {
|
||||
writeStringAttribute(out, ATTR_SESSION_STAGE_CID, session.stageCid);
|
||||
}
|
||||
writeBooleanAttribute(out, ATTR_SEALED, session.isSealed());
|
||||
|
||||
@ -479,6 +481,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: treat INHERIT_EXISTING as install for user
|
||||
|
||||
// Figure out where we're going to be staging session data
|
||||
final boolean stageInternal;
|
||||
|
||||
@ -502,22 +506,36 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
} else if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
|
||||
// We always stage inheriting sessions on internal storage first,
|
||||
// since we don't want to grow containers until we're sure that
|
||||
// everything looks legit.
|
||||
stageInternal = true;
|
||||
checkInternalStorage(params.sizeBytes);
|
||||
|
||||
// If we have a good hunch we'll end up on external storage, verify
|
||||
// free space there too.
|
||||
final ApplicationInfo info = mPm.getApplicationInfo(params.appPackageName, 0,
|
||||
// Inheriting existing install, so stay on the same storage medium.
|
||||
final ApplicationInfo existingApp = mPm.getApplicationInfo(params.appPackageName, 0,
|
||||
userId);
|
||||
if (info != null && (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
|
||||
checkExternalStorage(params.sizeBytes);
|
||||
|
||||
throw new UnsupportedOperationException("TODO: finish fleshing out ASEC support");
|
||||
if (existingApp == null) {
|
||||
throw new IllegalStateException(
|
||||
"Missing existing app " + params.appPackageName);
|
||||
}
|
||||
|
||||
final long existingSize;
|
||||
try {
|
||||
final PackageLite existingPkg = PackageParser.parsePackageLite(
|
||||
new File(existingApp.getCodePath()), 0);
|
||||
existingSize = PackageHelper.calculateInstalledSize(existingPkg, false,
|
||||
params.abiOverride);
|
||||
} catch (PackageParserException e) {
|
||||
throw new IllegalStateException(
|
||||
"Failed to calculate size of " + params.appPackageName);
|
||||
}
|
||||
|
||||
if ((existingApp.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0) {
|
||||
// Internal we can link existing install into place, so we only
|
||||
// need enough space for the new data.
|
||||
checkInternalStorage(params.sizeBytes);
|
||||
stageInternal = true;
|
||||
} else {
|
||||
// External we're going to copy existing install into our
|
||||
// container, so we need footprint of both.
|
||||
checkExternalStorage(params.sizeBytes + existingSize);
|
||||
stageInternal = false;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid install mode: " + params.mode);
|
||||
}
|
||||
@ -641,11 +659,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
}
|
||||
|
||||
final String cid = "smdl" + sessionId + ".tmp";
|
||||
|
||||
// Round up to nearest MB, plus another MB for filesystem overhead
|
||||
final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1;
|
||||
|
||||
if (PackageHelper.createSdDir(sizeMb, cid, PackageManagerService.getEncryptKey(),
|
||||
if (PackageHelper.createSdDir(sizeBytes, cid, PackageManagerService.getEncryptKey(),
|
||||
Process.SYSTEM_UID, true) == null) {
|
||||
throw new IOException("Failed to create ASEC");
|
||||
}
|
||||
@ -857,7 +871,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
final String existing = extras.getString(
|
||||
PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
|
||||
if (!TextUtils.isEmpty(existing)) {
|
||||
fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, existing);
|
||||
fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
@ -19,6 +19,7 @@ package com.android.server.pm;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
|
||||
@ -38,6 +39,7 @@ import android.content.pm.PackageInstaller.SessionParams;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageParser.ApkLite;
|
||||
import android.content.pm.PackageParser.PackageLite;
|
||||
import android.content.pm.PackageParser.PackageParserException;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.Bundle;
|
||||
@ -47,6 +49,7 @@ import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.system.ErrnoException;
|
||||
@ -59,18 +62,21 @@ import android.util.MathUtils;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.content.NativeLibraryHelper;
|
||||
import com.android.internal.content.PackageHelper;
|
||||
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.IoUtils;
|
||||
import libcore.io.Libcore;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
@ -95,18 +101,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
final SessionParams params;
|
||||
final long createdMillis;
|
||||
|
||||
/** Internal location where staged data is written. */
|
||||
final File internalStageDir;
|
||||
/** External container where staged data is written. */
|
||||
final String externalStageCid;
|
||||
|
||||
/**
|
||||
* When a {@link SessionParams#MODE_INHERIT_EXISTING} session is installed
|
||||
* into an ASEC, this is the container where the stage is combined with the
|
||||
* existing install.
|
||||
*/
|
||||
// TODO: persist this cid once we start splicing
|
||||
String combinedCid;
|
||||
/** Staging location where client data is written. */
|
||||
final File stageDir;
|
||||
final String stageCid;
|
||||
|
||||
/** Note that UID is not persisted; it's always derived at runtime. */
|
||||
final int installerUid;
|
||||
@ -132,20 +129,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
private int mFinalStatus;
|
||||
private String mFinalMessage;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private File mResolvedStageDir;
|
||||
|
||||
/**
|
||||
* Path to the resolved base APK for this session, which may point at an APK
|
||||
* inside the session (when the session defines the base), or it may point
|
||||
* at the existing base APK (when adding splits to an existing app).
|
||||
* <p>
|
||||
* This is used when confirming permissions, since we can't fully stage the
|
||||
* session inside an ASEC before confirming with user.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private String mResolvedBaseCodePath;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private ArrayList<FileBridge> mBridges = new ArrayList<>();
|
||||
|
||||
@ -157,6 +140,25 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
private int mVersionCode;
|
||||
private Signature[] mSignatures;
|
||||
|
||||
/**
|
||||
* Path to the validated base APK for this session, which may point at an
|
||||
* APK inside the session (when the session defines the base), or it may
|
||||
* point at the existing base APK (when adding splits to an existing app).
|
||||
* <p>
|
||||
* This is used when confirming permissions, since we can't fully stage the
|
||||
* session inside an ASEC before confirming with user.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private File mResolvedBaseFile;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private File mResolvedStageDir;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final List<File> mResolvedStagedFiles = new ArrayList<>();
|
||||
@GuardedBy("mLock")
|
||||
private final List<File> mResolvedInheritedFiles = new ArrayList<>();
|
||||
|
||||
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
@ -168,9 +170,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
try {
|
||||
commitLocked();
|
||||
} catch (PackageManagerException e) {
|
||||
Slog.e(TAG, "Install failed: " + e);
|
||||
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
|
||||
Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
|
||||
destroyInternal();
|
||||
dispatchSessionFinished(e.error, e.getMessage(), null);
|
||||
dispatchSessionFinished(e.error, completeMsg, null);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -181,7 +184,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
|
||||
Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
|
||||
String installerPackageName, SessionParams params, long createdMillis,
|
||||
File internalStageDir, String externalStageCid, boolean sealed) {
|
||||
File stageDir, String stageCid, boolean sealed) {
|
||||
mCallback = callback;
|
||||
mContext = context;
|
||||
mPm = pm;
|
||||
@ -192,12 +195,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
this.installerPackageName = installerPackageName;
|
||||
this.params = params;
|
||||
this.createdMillis = createdMillis;
|
||||
this.internalStageDir = internalStageDir;
|
||||
this.externalStageCid = externalStageCid;
|
||||
this.stageDir = stageDir;
|
||||
this.stageCid = stageCid;
|
||||
|
||||
if ((internalStageDir == null) == (externalStageCid == null)) {
|
||||
if ((stageDir == null) == (stageCid == null)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Exactly one of internal or external stage must be set");
|
||||
"Exactly one of stageDir or stageCid stage must be set");
|
||||
}
|
||||
|
||||
mSealed = sealed;
|
||||
@ -220,7 +223,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
synchronized (mLock) {
|
||||
info.sessionId = sessionId;
|
||||
info.installerPackageName = installerPackageName;
|
||||
info.resolvedBaseCodePath = mResolvedBaseCodePath;
|
||||
info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
|
||||
mResolvedBaseFile.getAbsolutePath() : null;
|
||||
info.progress = mProgress;
|
||||
info.sealed = mSealed;
|
||||
info.open = mOpenCount.get() > 0;
|
||||
@ -253,18 +257,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
* might point at an ASEC mount point, which is why we delay path resolution
|
||||
* until someone actively works with the session.
|
||||
*/
|
||||
private File getStageDir() throws IOException {
|
||||
private File resolveStageDir() throws IOException {
|
||||
synchronized (mLock) {
|
||||
if (mResolvedStageDir == null) {
|
||||
if (internalStageDir != null) {
|
||||
mResolvedStageDir = internalStageDir;
|
||||
if (stageDir != null) {
|
||||
mResolvedStageDir = stageDir;
|
||||
} else {
|
||||
final String path = PackageHelper.getSdDir(externalStageCid);
|
||||
final String path = PackageHelper.getSdDir(stageCid);
|
||||
if (path != null) {
|
||||
mResolvedStageDir = new File(path);
|
||||
} else {
|
||||
throw new IOException(
|
||||
"Failed to resolve container path for " + externalStageCid);
|
||||
throw new IOException("Failed to resolve path to container " + stageCid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -306,7 +309,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
public String[] getNames() {
|
||||
assertNotSealed("getNames");
|
||||
try {
|
||||
return getStageDir().list();
|
||||
return resolveStageDir().list();
|
||||
} catch (IOException e) {
|
||||
throw ExceptionUtils.wrap(e);
|
||||
}
|
||||
@ -339,8 +342,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
if (!FileUtils.isValidExtFilename(name)) {
|
||||
throw new IllegalArgumentException("Invalid name: " + name);
|
||||
}
|
||||
final File target = new File(getStageDir(), name);
|
||||
final File target = new File(resolveStageDir(), name);
|
||||
|
||||
// TODO: this should delegate to DCS so the system process avoids
|
||||
// holding open FDs into containers.
|
||||
final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
|
||||
O_CREAT | O_WRONLY, 0644);
|
||||
Os.chmod(target.getAbsolutePath(), 0644);
|
||||
@ -350,7 +355,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
if (lengthBytes > 0) {
|
||||
final StructStat stat = Libcore.os.fstat(targetFd);
|
||||
final long deltaBytes = lengthBytes - stat.st_size;
|
||||
if (deltaBytes > 0) {
|
||||
// Only need to free up space when writing to internal stage
|
||||
if (stageDir != null && deltaBytes > 0) {
|
||||
mPm.freeStorage(deltaBytes);
|
||||
}
|
||||
Libcore.os.posix_fallocate(targetFd, 0, lengthBytes);
|
||||
@ -385,7 +391,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
if (!FileUtils.isValidExtFilename(name)) {
|
||||
throw new IllegalArgumentException("Invalid name: " + name);
|
||||
}
|
||||
final File target = new File(getStageDir(), name);
|
||||
final File target = new File(resolveStageDir(), name);
|
||||
|
||||
final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), O_RDONLY, 0);
|
||||
return new ParcelFileDescriptor(targetFd);
|
||||
@ -424,22 +430,21 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
mCallback.onSessionSealed(this);
|
||||
}
|
||||
|
||||
final File stageDir;
|
||||
try {
|
||||
stageDir = getStageDir();
|
||||
resolveStageDir();
|
||||
} catch (IOException e) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
|
||||
"Failed to resolve stage dir", e);
|
||||
"Failed to resolve stage location", e);
|
||||
}
|
||||
|
||||
// Verify that stage looks sane with respect to existing application.
|
||||
// This currently only ensures packageName, versionCode, and certificate
|
||||
// consistency.
|
||||
validateInstallLocked(stageDir);
|
||||
validateInstallLocked();
|
||||
|
||||
Preconditions.checkNotNull(mPackageName);
|
||||
Preconditions.checkNotNull(mSignatures);
|
||||
Preconditions.checkNotNull(mResolvedBaseCodePath);
|
||||
Preconditions.checkNotNull(mResolvedBaseFile);
|
||||
|
||||
if (!mPermissionsAccepted) {
|
||||
// User needs to accept permissions; give installer an intent they
|
||||
@ -454,17 +459,41 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stageCid != null) {
|
||||
// Figure out the final installed size and resize the container once
|
||||
// and for all. Internally the parser handles straddling between two
|
||||
// locations when inheriting.
|
||||
final long finalSize = calculateInstalledSize();
|
||||
resizeContainer(stageCid, finalSize);
|
||||
}
|
||||
|
||||
// Inherit any packages and native libraries from existing install that
|
||||
// haven't been overridden.
|
||||
if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
|
||||
// TODO: implement splicing into existing ASEC
|
||||
spliceExistingFilesIntoStage(stageDir);
|
||||
try {
|
||||
if (stageCid != null) {
|
||||
// TODO: this should delegate to DCS so the system process
|
||||
// avoids holding open FDs into containers.
|
||||
copyFiles(mResolvedInheritedFiles, resolveStageDir());
|
||||
} else {
|
||||
linkFiles(mResolvedInheritedFiles, resolveStageDir());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
|
||||
"Failed to inherit existing install", e);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: surface more granular state from dexopt
|
||||
mCallback.onSessionProgressChanged(this, 0.9f);
|
||||
|
||||
// TODO: for ASEC based applications, grow and stream in packages
|
||||
// Unpack native libraries
|
||||
extractNativeLibraries(mResolvedStageDir, params.abiOverride);
|
||||
|
||||
// Container is ready to go, let's seal it up!
|
||||
if (stageCid != null) {
|
||||
finalizeAndFixContainer(stageCid);
|
||||
}
|
||||
|
||||
// We've reached point of no return; call into PMS to install the stage.
|
||||
// Regardless of success or failure we always destroy session.
|
||||
@ -482,7 +511,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
};
|
||||
|
||||
mPm.installStage(mPackageName, this.internalStageDir, this.externalStageCid, localObserver,
|
||||
mPm.installStage(mPackageName, stageDir, stageCid, localObserver,
|
||||
params, installerPackageName, installerUid, new UserHandle(userId));
|
||||
}
|
||||
|
||||
@ -490,81 +519,88 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
* Validate install by confirming that all application packages are have
|
||||
* consistent package name, version code, and signing certificates.
|
||||
* <p>
|
||||
* Clears and populates {@link #mResolvedBaseFile},
|
||||
* {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
|
||||
* <p>
|
||||
* Renames package files in stage to match split names defined inside.
|
||||
* <p>
|
||||
* Note that upgrade compatibility is still performed by
|
||||
* {@link PackageManagerService}.
|
||||
*/
|
||||
private void validateInstallLocked(File stageDir) throws PackageManagerException {
|
||||
private void validateInstallLocked() throws PackageManagerException {
|
||||
mPackageName = null;
|
||||
mVersionCode = -1;
|
||||
mSignatures = null;
|
||||
mResolvedBaseCodePath = null;
|
||||
|
||||
final File[] files = stageDir.listFiles();
|
||||
mResolvedBaseFile = null;
|
||||
mResolvedStagedFiles.clear();
|
||||
mResolvedInheritedFiles.clear();
|
||||
|
||||
final File[] files = mResolvedStageDir.listFiles();
|
||||
if (ArrayUtils.isEmpty(files)) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
|
||||
}
|
||||
|
||||
// Verify that all staged packages are internally consistent
|
||||
final ArraySet<String> seenSplits = new ArraySet<>();
|
||||
final ArraySet<String> stagedSplits = new ArraySet<>();
|
||||
for (File file : files) {
|
||||
|
||||
// Installers can't stage directories, so it's fine to ignore
|
||||
// entries like "lost+found".
|
||||
if (file.isDirectory()) continue;
|
||||
|
||||
final ApkLite info;
|
||||
final ApkLite apk;
|
||||
try {
|
||||
info = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
|
||||
apk = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
|
||||
} catch (PackageParserException e) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
|
||||
"Failed to parse " + file + ": " + e);
|
||||
}
|
||||
|
||||
if (!seenSplits.add(info.splitName)) {
|
||||
if (!stagedSplits.add(apk.splitName)) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
|
||||
"Split " + info.splitName + " was defined multiple times");
|
||||
"Split " + apk.splitName + " was defined multiple times");
|
||||
}
|
||||
|
||||
// Use first package to define unknown values
|
||||
if (mPackageName == null) {
|
||||
mPackageName = info.packageName;
|
||||
mVersionCode = info.versionCode;
|
||||
mPackageName = apk.packageName;
|
||||
mVersionCode = apk.versionCode;
|
||||
}
|
||||
if (mSignatures == null) {
|
||||
mSignatures = info.signatures;
|
||||
mSignatures = apk.signatures;
|
||||
}
|
||||
|
||||
assertPackageConsistent(String.valueOf(file), info.packageName, info.versionCode,
|
||||
info.signatures);
|
||||
assertApkConsistent(String.valueOf(file), apk);
|
||||
|
||||
// Take this opportunity to enforce uniform naming
|
||||
final String targetName;
|
||||
if (info.splitName == null) {
|
||||
if (apk.splitName == null) {
|
||||
targetName = "base.apk";
|
||||
} else {
|
||||
targetName = "split_" + info.splitName + ".apk";
|
||||
targetName = "split_" + apk.splitName + ".apk";
|
||||
}
|
||||
if (!FileUtils.isValidExtFilename(targetName)) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
|
||||
"Invalid filename: " + targetName);
|
||||
}
|
||||
|
||||
final File targetFile = new File(stageDir, targetName);
|
||||
final File targetFile = new File(mResolvedStageDir, targetName);
|
||||
if (!file.equals(targetFile)) {
|
||||
file.renameTo(targetFile);
|
||||
}
|
||||
|
||||
// Base is coming from session
|
||||
if (info.splitName == null) {
|
||||
mResolvedBaseCodePath = targetFile.getAbsolutePath();
|
||||
if (apk.splitName == null) {
|
||||
mResolvedBaseFile = targetFile;
|
||||
}
|
||||
|
||||
mResolvedStagedFiles.add(targetFile);
|
||||
}
|
||||
|
||||
if (params.mode == SessionParams.MODE_FULL_INSTALL) {
|
||||
// Full installs must include a base package
|
||||
if (!seenSplits.contains(null)) {
|
||||
if (!stagedSplits.contains(null)) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
|
||||
"Full install must include a base package");
|
||||
}
|
||||
@ -577,67 +613,204 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
"Missing existing base package for " + mPackageName);
|
||||
}
|
||||
|
||||
// Base might be inherited from existing install
|
||||
if (mResolvedBaseCodePath == null) {
|
||||
mResolvedBaseCodePath = app.getBaseCodePath();
|
||||
}
|
||||
|
||||
final ApkLite info;
|
||||
final PackageLite existing;
|
||||
final ApkLite existingBase;
|
||||
try {
|
||||
info = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
|
||||
existing = PackageParser.parsePackageLite(new File(app.getCodePath()), 0);
|
||||
existingBase = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
|
||||
PackageParser.PARSE_COLLECT_CERTIFICATES);
|
||||
} catch (PackageParserException e) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
|
||||
"Failed to parse existing base " + app.getBaseCodePath() + ": " + e);
|
||||
"Failed to parse existing package " + app.getCodePath() + ": " + e);
|
||||
}
|
||||
|
||||
assertPackageConsistent("Existing base", info.packageName, info.versionCode,
|
||||
info.signatures);
|
||||
assertApkConsistent("Existing base", existingBase);
|
||||
|
||||
// Inherit base if not overridden
|
||||
if (mResolvedBaseFile == null) {
|
||||
mResolvedBaseFile = new File(app.getBaseCodePath());
|
||||
mResolvedInheritedFiles.add(mResolvedBaseFile);
|
||||
}
|
||||
|
||||
// Inherit splits if not overridden
|
||||
if (!ArrayUtils.isEmpty(existing.splitNames)) {
|
||||
for (int i = 0; i < existing.splitNames.length; i++) {
|
||||
final String splitName = existing.splitNames[i];
|
||||
final File splitFile = new File(existing.splitCodePaths[i]);
|
||||
|
||||
if (!stagedSplits.contains(splitName)) {
|
||||
mResolvedInheritedFiles.add(splitFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void assertPackageConsistent(String tag, String packageName, int versionCode,
|
||||
Signature[] signatures) throws PackageManagerException {
|
||||
if (!mPackageName.equals(packageName)) {
|
||||
private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
|
||||
if (!mPackageName.equals(apk.packageName)) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
|
||||
+ packageName + " inconsistent with " + mPackageName);
|
||||
+ apk.packageName + " inconsistent with " + mPackageName);
|
||||
}
|
||||
if (mVersionCode != versionCode) {
|
||||
if (mVersionCode != apk.versionCode) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
|
||||
+ " version code " + versionCode + " inconsistent with "
|
||||
+ " version code " + apk.versionCode + " inconsistent with "
|
||||
+ mVersionCode);
|
||||
}
|
||||
if (!Signature.areExactMatch(mSignatures, signatures)) {
|
||||
if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
|
||||
tag + " signatures are inconsistent");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Application is already installed; splice existing files that haven't been
|
||||
* overridden into our stage.
|
||||
* Calculate the final install footprint size, combining both staged and
|
||||
* existing APKs together and including unpacked native code from both.
|
||||
*/
|
||||
private void spliceExistingFilesIntoStage(File stageDir) throws PackageManagerException {
|
||||
final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
|
||||
private long calculateInstalledSize() throws PackageManagerException {
|
||||
Preconditions.checkNotNull(mResolvedBaseFile);
|
||||
|
||||
int n = 0;
|
||||
final File[] oldFiles = new File(app.getCodePath()).listFiles();
|
||||
if (!ArrayUtils.isEmpty(oldFiles)) {
|
||||
for (File oldFile : oldFiles) {
|
||||
if (!PackageParser.isApkFile(oldFile)) continue;
|
||||
final ApkLite baseApk;
|
||||
try {
|
||||
baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
|
||||
} catch (PackageParserException e) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
|
||||
"Failed to parse base package " + mResolvedBaseFile + ": " + e);
|
||||
}
|
||||
|
||||
final File newFile = new File(stageDir, oldFile.getName());
|
||||
try {
|
||||
Os.link(oldFile.getAbsolutePath(), newFile.getAbsolutePath());
|
||||
n++;
|
||||
} catch (ErrnoException e) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
||||
"Failed to splice into stage", e);
|
||||
}
|
||||
final List<String> splitPaths = new ArrayList<>();
|
||||
for (File file : mResolvedStagedFiles) {
|
||||
if (mResolvedBaseFile.equals(file)) continue;
|
||||
splitPaths.add(file.getAbsolutePath());
|
||||
}
|
||||
for (File file : mResolvedInheritedFiles) {
|
||||
if (mResolvedBaseFile.equals(file)) continue;
|
||||
splitPaths.add(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
// This is kind of hacky; we're creating a half-parsed package that is
|
||||
// straddled between the inherited and staged APKs.
|
||||
final PackageLite pkg = new PackageLite(null, baseApk, null,
|
||||
splitPaths.toArray(new String[splitPaths.size()]));
|
||||
final boolean isForwardLocked =
|
||||
(params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
|
||||
|
||||
try {
|
||||
return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, params.abiOverride);
|
||||
} catch (IOException e) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
|
||||
"Failed to calculate install size", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void linkFiles(List<File> fromFiles, File toDir) throws IOException {
|
||||
for (File fromFile : fromFiles) {
|
||||
final File toFile = new File(toDir, fromFile.getName());
|
||||
try {
|
||||
if (LOGD) Slog.d(TAG, "Linking " + fromFile + " to " + toFile);
|
||||
Os.link(fromFile.getAbsolutePath(), toFile.getAbsolutePath());
|
||||
} catch (ErrnoException e) {
|
||||
throw new IOException("Failed to link " + fromFile + " to " + toFile, e);
|
||||
}
|
||||
}
|
||||
Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
|
||||
}
|
||||
|
||||
private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
|
||||
// Remove any partial files from previous attempt
|
||||
for (File file : toDir.listFiles()) {
|
||||
if (file.getName().endsWith(".tmp")) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
if (LOGD) Slog.d(TAG, "Spliced " + n + " existing APKs into stage");
|
||||
for (File fromFile : fromFiles) {
|
||||
final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
|
||||
if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
|
||||
if (!FileUtils.copyFile(fromFile, tmpFile)) {
|
||||
throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
|
||||
}
|
||||
|
||||
final File toFile = new File(toDir, fromFile.getName());
|
||||
if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
|
||||
if (!tmpFile.renameTo(toFile)) {
|
||||
throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
|
||||
}
|
||||
}
|
||||
Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
|
||||
}
|
||||
|
||||
private static void extractNativeLibraries(File packageDir, String abiOverride)
|
||||
throws PackageManagerException {
|
||||
if (LOGD) Slog.v(TAG, "extractNativeLibraries()");
|
||||
|
||||
// Always start from a clean slate
|
||||
final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
|
||||
NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
|
||||
|
||||
NativeLibraryHelper.Handle handle = null;
|
||||
try {
|
||||
handle = NativeLibraryHelper.Handle.create(packageDir);
|
||||
final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
|
||||
abiOverride);
|
||||
if (res != PackageManager.INSTALL_SUCCEEDED) {
|
||||
throw new PackageManagerException(res,
|
||||
"Failed to extract native libraries, res=" + res);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
||||
"Failed to extract native libraries", e);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(handle);
|
||||
}
|
||||
}
|
||||
|
||||
private static void resizeContainer(String cid, long targetSize)
|
||||
throws PackageManagerException {
|
||||
String path = PackageHelper.getSdDir(cid);
|
||||
if (path == null) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
|
||||
"Failed to find mounted " + cid);
|
||||
}
|
||||
|
||||
final long currentSize = new File(path).getTotalSpace();
|
||||
if (currentSize > targetSize) {
|
||||
Slog.w(TAG, "Current size " + currentSize + " is larger than target size "
|
||||
+ targetSize + "; skipping resize");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PackageHelper.unMountSdDir(cid)) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
|
||||
"Failed to unmount " + cid + " before resize");
|
||||
}
|
||||
|
||||
if (!PackageHelper.resizeSdDir(targetSize, cid,
|
||||
PackageManagerService.getEncryptKey())) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
|
||||
"Failed to resize " + cid + " to " + targetSize + " bytes");
|
||||
}
|
||||
|
||||
path = PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
|
||||
Process.SYSTEM_UID, false);
|
||||
if (path == null) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
|
||||
"Failed to mount " + cid + " after resize");
|
||||
}
|
||||
}
|
||||
|
||||
private void finalizeAndFixContainer(String cid) throws PackageManagerException {
|
||||
if (!PackageHelper.finalizeSdDir(cid)) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
|
||||
"Failed to finalize container " + cid);
|
||||
}
|
||||
|
||||
final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
|
||||
UserHandle.USER_OWNER);
|
||||
final int gid = UserHandle.getSharedAppGid(uid);
|
||||
if (!PackageHelper.fixSdPermissions(cid, gid, null)) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
|
||||
"Failed to fix permissions on container " + cid);
|
||||
}
|
||||
}
|
||||
|
||||
void setPermissionsResult(boolean accepted) {
|
||||
@ -694,12 +867,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
mSealed = true;
|
||||
mDestroyed = true;
|
||||
}
|
||||
if (internalStageDir != null) {
|
||||
FileUtils.deleteContents(internalStageDir);
|
||||
internalStageDir.delete();
|
||||
if (stageDir != null) {
|
||||
FileUtils.deleteContents(stageDir);
|
||||
stageDir.delete();
|
||||
}
|
||||
if (externalStageCid != null) {
|
||||
PackageHelper.destroySdDir(externalStageCid);
|
||||
if (stageCid != null) {
|
||||
PackageHelper.destroySdDir(stageCid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,8 +890,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
pw.printPair("installerPackageName", installerPackageName);
|
||||
pw.printPair("installerUid", installerUid);
|
||||
pw.printPair("createdMillis", createdMillis);
|
||||
pw.printPair("internalStageDir", internalStageDir);
|
||||
pw.printPair("externalStageCid", externalStageCid);
|
||||
pw.printPair("stageDir", stageDir);
|
||||
pw.printPair("stageCid", stageCid);
|
||||
pw.println();
|
||||
|
||||
params.dump(pw);
|
||||
|
@ -50,6 +50,8 @@ import static android.system.OsConstants.O_CREAT;
|
||||
import static android.system.OsConstants.O_RDWR;
|
||||
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
|
||||
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
|
||||
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
|
||||
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
|
||||
import static com.android.internal.util.ArrayUtils.appendInt;
|
||||
import static com.android.internal.util.ArrayUtils.removeInt;
|
||||
|
||||
@ -298,9 +300,6 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
|
||||
|
||||
private static final String LIB_DIR_NAME = "lib";
|
||||
private static final String LIB64_DIR_NAME = "lib64";
|
||||
|
||||
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
|
||||
|
||||
private static String sPreferredInstructionSet;
|
||||
@ -1121,7 +1120,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
if ((state != null) && !state.timeoutExtended()) {
|
||||
final InstallArgs args = state.getInstallArgs();
|
||||
final Uri originUri = Uri.fromFile(args.originFile);
|
||||
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
|
||||
|
||||
Slog.i(TAG, "Verification timed out for " + originUri);
|
||||
mPendingVerification.remove(verificationId);
|
||||
@ -1168,7 +1167,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
mPendingVerification.remove(verificationId);
|
||||
|
||||
final InstallArgs args = state.getInstallArgs();
|
||||
final Uri originUri = Uri.fromFile(args.originFile);
|
||||
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
|
||||
|
||||
int ret;
|
||||
if (state.isInstallAllowed()) {
|
||||
@ -4271,7 +4270,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
|
||||
ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
|
||||
getAppDexInstructionSets(ps), isMultiArch(ps));
|
||||
getAppDexInstructionSets(ps));
|
||||
synchronized (mInstallLock) {
|
||||
args.cleanUpResourcesLI();
|
||||
}
|
||||
@ -4334,7 +4333,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
+ " better than installed " + ps.versionCode);
|
||||
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
|
||||
ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
|
||||
getAppDexInstructionSets(ps), isMultiArch(ps));
|
||||
getAppDexInstructionSets(ps));
|
||||
synchronized (mInstallLock) {
|
||||
args.cleanUpResourcesLI();
|
||||
}
|
||||
@ -5527,8 +5526,9 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
if (isAsec) {
|
||||
abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
|
||||
} else {
|
||||
abi32 = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
|
||||
nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS, useIsaSpecificSubdirs);
|
||||
abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
||||
nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
|
||||
useIsaSpecificSubdirs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5539,8 +5539,9 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
if (isAsec) {
|
||||
abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
|
||||
} else {
|
||||
abi64 = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
|
||||
nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS, useIsaSpecificSubdirs);
|
||||
abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
||||
nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
|
||||
useIsaSpecificSubdirs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5578,7 +5579,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
if (isAsec) {
|
||||
copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
|
||||
} else {
|
||||
copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle,
|
||||
copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
||||
nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
|
||||
}
|
||||
|
||||
@ -7782,7 +7783,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
verificationParams.setInstallerUid(uid);
|
||||
|
||||
final Message msg = mHandler.obtainMessage(INIT_COPY);
|
||||
msg.obj = new InstallParams(originFile, null, false, observer, filteredFlags,
|
||||
final OriginInfo origin = new OriginInfo(originFile, null, false);
|
||||
msg.obj = new InstallParams(origin, observer, filteredFlags,
|
||||
installerPackageName, verificationParams, user, packageAbiOverride);
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
@ -7794,7 +7796,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
params.referrerUri, installerUid, null);
|
||||
|
||||
final Message msg = mHandler.obtainMessage(INIT_COPY);
|
||||
msg.obj = new InstallParams(stagedDir, stagedCid, true, observer, params.installFlags,
|
||||
final OriginInfo origin = new OriginInfo(stagedDir, stagedCid, true);
|
||||
msg.obj = new InstallParams(origin, observer, params.installFlags,
|
||||
installerPackageName, verifParams, user, params.abiOverride);
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
@ -8487,22 +8490,45 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
class InstallParams extends HandlerParams {
|
||||
static class OriginInfo {
|
||||
/**
|
||||
* Location where install is coming from, before it has been
|
||||
* copied/renamed into place. This could be a single monolithic APK
|
||||
* file, or a cluster directory. This location may be untrusted.
|
||||
*/
|
||||
final File originFile;
|
||||
final String originCid;
|
||||
final File file;
|
||||
final String cid;
|
||||
|
||||
/**
|
||||
* Flag indicating that {@link #originFile} or {@link #originCid} has
|
||||
* already been staged, meaning downstream users don't need to
|
||||
* defensively copy the contents.
|
||||
* Flag indicating that {@link #file} or {@link #cid} has already been
|
||||
* staged, meaning downstream users don't need to defensively copy the
|
||||
* contents.
|
||||
*/
|
||||
boolean originStaged;
|
||||
final boolean staged;
|
||||
|
||||
final String resolvedPath;
|
||||
final File resolvedFile;
|
||||
|
||||
public OriginInfo(File file, String cid, boolean staged) {
|
||||
this.file = file;
|
||||
this.cid = cid;
|
||||
this.staged = staged;
|
||||
|
||||
if (cid != null) {
|
||||
resolvedPath = PackageHelper.getSdDir(cid);
|
||||
resolvedFile = new File(resolvedPath);
|
||||
} else if (file != null) {
|
||||
resolvedPath = file.getAbsolutePath();
|
||||
resolvedFile = file;
|
||||
} else {
|
||||
resolvedPath = null;
|
||||
resolvedFile = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InstallParams extends HandlerParams {
|
||||
final OriginInfo origin;
|
||||
final IPackageInstallObserver2 observer;
|
||||
int flags;
|
||||
final String installerPackageName;
|
||||
@ -8510,15 +8536,12 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
private InstallArgs mArgs;
|
||||
private int mRet;
|
||||
final String packageAbiOverride;
|
||||
boolean multiArch;
|
||||
|
||||
InstallParams(File originFile, String originCid, boolean originStaged,
|
||||
IPackageInstallObserver2 observer, int flags, String installerPackageName,
|
||||
VerificationParams verificationParams, UserHandle user, String packageAbiOverride) {
|
||||
InstallParams(OriginInfo origin, IPackageInstallObserver2 observer, int flags,
|
||||
String installerPackageName, VerificationParams verificationParams, UserHandle user,
|
||||
String packageAbiOverride) {
|
||||
super(user);
|
||||
this.originFile = originFile;
|
||||
this.originCid = originCid;
|
||||
this.originStaged = originStaged;
|
||||
this.origin = origin;
|
||||
this.observer = observer;
|
||||
this.flags = flags;
|
||||
this.installerPackageName = installerPackageName;
|
||||
@ -8529,7 +8552,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
|
||||
+ " file=" + originFile + " cid=" + originCid + "}";
|
||||
+ " file=" + origin.file + " cid=" + origin.cid + "}";
|
||||
}
|
||||
|
||||
public ManifestDigest getManifestDigest() {
|
||||
@ -8608,11 +8631,11 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
int ret = PackageManager.INSTALL_SUCCEEDED;
|
||||
|
||||
// If we're already staged, we've firmly committed to an install location
|
||||
if (originStaged) {
|
||||
if (originFile != null) {
|
||||
if (origin.staged) {
|
||||
if (origin.file != null) {
|
||||
flags |= PackageManager.INSTALL_INTERNAL;
|
||||
flags &= ~PackageManager.INSTALL_EXTERNAL;
|
||||
} else if (originCid != null) {
|
||||
} else if (origin.cid != null) {
|
||||
flags |= PackageManager.INSTALL_EXTERNAL;
|
||||
flags &= ~PackageManager.INSTALL_INTERNAL;
|
||||
} else {
|
||||
@ -8622,6 +8645,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
final boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0;
|
||||
final boolean onInt = (flags & PackageManager.INSTALL_INTERNAL) != 0;
|
||||
|
||||
PackageInfoLite pkgLite = null;
|
||||
|
||||
if (onInt && onSd) {
|
||||
@ -8629,21 +8653,14 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
|
||||
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
|
||||
} else {
|
||||
// Remote call to find out default install location
|
||||
final String originPath = originFile.getAbsolutePath();
|
||||
pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags,
|
||||
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, flags,
|
||||
packageAbiOverride);
|
||||
// Keep track of whether this package is a multiArch package until
|
||||
// we perform a full scan of it. We need to do this because we might
|
||||
// end up extracting the package shared libraries before we perform
|
||||
// a full scan.
|
||||
multiArch = pkgLite.multiArch;
|
||||
|
||||
/*
|
||||
* If we have too little free space, try to free cache
|
||||
* before giving up.
|
||||
*/
|
||||
if (!originStaged && pkgLite.recommendedInstallLocation
|
||||
if (!origin.staged && pkgLite.recommendedInstallLocation
|
||||
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
|
||||
// TODO: focus freeing disk space on the target device
|
||||
final StorageManager storage = StorageManager.from(mContext);
|
||||
@ -8651,11 +8668,11 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
Environment.getDataDirectory());
|
||||
|
||||
final long sizeBytes = mContainerService.calculateInstalledSize(
|
||||
originPath, isForwardLocked(), packageAbiOverride);
|
||||
origin.resolvedPath, isForwardLocked(), packageAbiOverride);
|
||||
|
||||
if (mInstaller.freeCache(sizeBytes + lowThreshold) >= 0) {
|
||||
pkgLite = mContainerService.getMinimalPackageInfo(originPath, flags,
|
||||
packageAbiOverride);
|
||||
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
|
||||
flags, packageAbiOverride);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -8729,10 +8746,10 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
final int requiredUid = mRequiredVerifierPackage == null ? -1
|
||||
: getPackageUid(mRequiredVerifierPackage, userIdentifier);
|
||||
if (requiredUid != -1 && isVerificationEnabled(userIdentifier, flags)) {
|
||||
// TODO: send verifier the install session instead of uri
|
||||
final Intent verification = new Intent(
|
||||
Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
|
||||
verification.setDataAndType(Uri.fromFile(originFile), PACKAGE_MIME_TYPE);
|
||||
verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
|
||||
PACKAGE_MIME_TYPE);
|
||||
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
|
||||
final List<ResolveInfo> receivers = queryIntentReceivers(verification,
|
||||
@ -8890,8 +8907,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
int mRet;
|
||||
|
||||
MoveParams(InstallArgs srcArgs, IPackageMoveObserver observer, int flags,
|
||||
String packageName, String[] instructionSets, int uid, UserHandle user,
|
||||
boolean isMultiArch) {
|
||||
String packageName, String[] instructionSets, int uid, UserHandle user) {
|
||||
super(user);
|
||||
this.srcArgs = srcArgs;
|
||||
this.observer = observer;
|
||||
@ -8901,7 +8917,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
if (srcArgs != null) {
|
||||
final String codePath = srcArgs.getCodePath();
|
||||
targetArgs = createInstallArgsForMoveTarget(codePath, flags, packageName,
|
||||
instructionSets, isMultiArch);
|
||||
instructionSets);
|
||||
} else {
|
||||
targetArgs = null;
|
||||
}
|
||||
@ -9002,8 +9018,6 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
private InstallArgs createInstallArgs(InstallParams params) {
|
||||
// TODO: extend to support incoming zero-copy locations
|
||||
|
||||
if (installOnSd(params.flags) || params.isForwardLocked()) {
|
||||
return new AsecInstallArgs(params);
|
||||
} else {
|
||||
@ -9016,8 +9030,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
* when cleaning up old installs, or used as a move source.
|
||||
*/
|
||||
private InstallArgs createInstallArgsForExisting(int flags, String codePath,
|
||||
String resourcePath, String nativeLibraryRoot, String[] instructionSets,
|
||||
boolean isMultiArch) {
|
||||
String resourcePath, String nativeLibraryRoot, String[] instructionSets) {
|
||||
final boolean isInAsec;
|
||||
if (installOnSd(flags)) {
|
||||
/* Apps on SD card are always in ASEC containers. */
|
||||
@ -9035,33 +9048,29 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
if (isInAsec) {
|
||||
return new AsecInstallArgs(codePath, instructionSets,
|
||||
installOnSd(flags), installForwardLocked(flags), isMultiArch);
|
||||
installOnSd(flags), installForwardLocked(flags));
|
||||
} else {
|
||||
return new FileInstallArgs(codePath, resourcePath, nativeLibraryRoot,
|
||||
instructionSets, isMultiArch);
|
||||
instructionSets);
|
||||
}
|
||||
}
|
||||
|
||||
private InstallArgs createInstallArgsForMoveTarget(String codePath, int flags, String pkgName,
|
||||
String[] instructionSets, boolean isMultiArch) {
|
||||
String[] instructionSets) {
|
||||
final File codeFile = new File(codePath);
|
||||
if (installOnSd(flags) || installForwardLocked(flags)) {
|
||||
String cid = getNextCodePath(codePath, pkgName, "/"
|
||||
+ AsecInstallArgs.RES_FILE_NAME);
|
||||
return new AsecInstallArgs(codeFile, cid, instructionSets, installOnSd(flags),
|
||||
installForwardLocked(flags), isMultiArch);
|
||||
installForwardLocked(flags));
|
||||
} else {
|
||||
return new FileInstallArgs(codeFile, instructionSets, isMultiArch);
|
||||
return new FileInstallArgs(codeFile, instructionSets);
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class InstallArgs {
|
||||
/** @see InstallParams#originFile */
|
||||
final File originFile;
|
||||
/** @see InstallParams#originStaged */
|
||||
final boolean originStaged;
|
||||
|
||||
// TODO: define inherit location
|
||||
/** @see InstallParams#origin */
|
||||
final OriginInfo origin;
|
||||
|
||||
final IPackageInstallObserver2 observer;
|
||||
// Always refers to PackageManager flags only
|
||||
@ -9070,19 +9079,16 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
final ManifestDigest manifestDigest;
|
||||
final UserHandle user;
|
||||
final String abiOverride;
|
||||
final boolean multiArch;
|
||||
|
||||
// The list of instruction sets supported by this app. This is currently
|
||||
// only used during the rmdex() phase to clean up resources. We can get rid of this
|
||||
// if we move dex files under the common app path.
|
||||
/* nullable */ String[] instructionSets;
|
||||
|
||||
InstallArgs(File originFile, boolean originStaged, IPackageInstallObserver2 observer,
|
||||
int flags, String installerPackageName, ManifestDigest manifestDigest,
|
||||
UserHandle user, String[] instructionSets,
|
||||
String abiOverride, boolean multiArch) {
|
||||
this.originFile = originFile;
|
||||
this.originStaged = originStaged;
|
||||
InstallArgs(OriginInfo origin, IPackageInstallObserver2 observer, int flags,
|
||||
String installerPackageName, ManifestDigest manifestDigest, UserHandle user,
|
||||
String[] instructionSets, String abiOverride) {
|
||||
this.origin = origin;
|
||||
this.flags = flags;
|
||||
this.observer = observer;
|
||||
this.installerPackageName = installerPackageName;
|
||||
@ -9090,7 +9096,6 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
this.user = user;
|
||||
this.instructionSets = instructionSets;
|
||||
this.abiOverride = abiOverride;
|
||||
this.multiArch = multiArch;
|
||||
}
|
||||
|
||||
abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
|
||||
@ -9161,10 +9166,9 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
/** New install */
|
||||
FileInstallArgs(InstallParams params) {
|
||||
super(params.originFile, params.originStaged, params.observer, params.flags,
|
||||
super(params.origin, params.observer, params.flags,
|
||||
params.installerPackageName, params.getManifestDigest(), params.getUser(),
|
||||
null /* instruction sets */, params.packageAbiOverride,
|
||||
params.multiArch);
|
||||
null /* instruction sets */, params.packageAbiOverride);
|
||||
if (isFwdLocked()) {
|
||||
throw new IllegalArgumentException("Forward locking only supported in ASEC");
|
||||
}
|
||||
@ -9172,8 +9176,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
/** Existing install */
|
||||
FileInstallArgs(String codePath, String resourcePath, String legacyNativeLibraryPath,
|
||||
String[] instructionSets, boolean isMultiArch) {
|
||||
super(null, false, null, 0, null, null, null, instructionSets, null, isMultiArch);
|
||||
String[] instructionSets) {
|
||||
super(new OriginInfo(null, null, false), null, 0, null, null, null, instructionSets, null);
|
||||
this.codeFile = (codePath != null) ? new File(codePath) : null;
|
||||
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
|
||||
this.legacyNativeLibraryPath = (legacyNativeLibraryPath != null) ?
|
||||
@ -9181,13 +9185,12 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
/** New install from existing */
|
||||
FileInstallArgs(File originFile, String[] instructionSets, boolean isMultiArch) {
|
||||
super(originFile, false, null, 0, null, null, null, instructionSets, null,
|
||||
isMultiArch);
|
||||
FileInstallArgs(File originFile, String[] instructionSets) {
|
||||
super(new OriginInfo(originFile, null, false), null, 0, null, null, null, instructionSets, null);
|
||||
}
|
||||
|
||||
boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
|
||||
final long sizeBytes = imcs.calculateInstalledSize(originFile.getAbsolutePath(),
|
||||
final long sizeBytes = imcs.calculateInstalledSize(origin.file.getAbsolutePath(),
|
||||
isFwdLocked(), abiOverride);
|
||||
|
||||
final StorageManager storage = StorageManager.from(mContext);
|
||||
@ -9195,53 +9198,53 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
|
||||
int ret = PackageManager.INSTALL_SUCCEEDED;
|
||||
if (origin.staged) {
|
||||
Slog.d(TAG, origin.file + " already staged; skipping copy");
|
||||
codeFile = origin.file;
|
||||
resourceFile = origin.file;
|
||||
return PackageManager.INSTALL_SUCCEEDED;
|
||||
}
|
||||
|
||||
if (originStaged) {
|
||||
Slog.d(TAG, originFile + " already staged; skipping copy");
|
||||
codeFile = originFile;
|
||||
resourceFile = originFile;
|
||||
} else {
|
||||
try {
|
||||
final File tempDir = mInstallerService.allocateInternalStageDirLegacy();
|
||||
codeFile = tempDir;
|
||||
resourceFile = tempDir;
|
||||
} catch (IOException e) {
|
||||
Slog.w(TAG, "Failed to create copy file: " + e);
|
||||
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||
}
|
||||
try {
|
||||
final File tempDir = mInstallerService.allocateInternalStageDirLegacy();
|
||||
codeFile = tempDir;
|
||||
resourceFile = tempDir;
|
||||
} catch (IOException e) {
|
||||
Slog.w(TAG, "Failed to create copy file: " + e);
|
||||
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||
}
|
||||
|
||||
final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
|
||||
@Override
|
||||
public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
|
||||
if (!FileUtils.isValidExtFilename(name)) {
|
||||
throw new IllegalArgumentException("Invalid filename: " + name);
|
||||
}
|
||||
try {
|
||||
final File file = new File(codeFile, name);
|
||||
final FileDescriptor fd = Os.open(file.getAbsolutePath(),
|
||||
O_RDWR | O_CREAT, 0644);
|
||||
Os.chmod(file.getAbsolutePath(), 0644);
|
||||
return new ParcelFileDescriptor(fd);
|
||||
} catch (ErrnoException e) {
|
||||
throw new RemoteException("Failed to open: " + e.getMessage());
|
||||
}
|
||||
final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
|
||||
@Override
|
||||
public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
|
||||
if (!FileUtils.isValidExtFilename(name)) {
|
||||
throw new IllegalArgumentException("Invalid filename: " + name);
|
||||
}
|
||||
try {
|
||||
final File file = new File(codeFile, name);
|
||||
final FileDescriptor fd = Os.open(file.getAbsolutePath(),
|
||||
O_RDWR | O_CREAT, 0644);
|
||||
Os.chmod(file.getAbsolutePath(), 0644);
|
||||
return new ParcelFileDescriptor(fd);
|
||||
} catch (ErrnoException e) {
|
||||
throw new RemoteException("Failed to open: " + e.getMessage());
|
||||
}
|
||||
};
|
||||
|
||||
ret = imcs.copyPackage(originFile.getAbsolutePath(), target);
|
||||
if (ret != PackageManager.INSTALL_SUCCEEDED) {
|
||||
Slog.e(TAG, "Failed to copy package");
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
int ret = PackageManager.INSTALL_SUCCEEDED;
|
||||
ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
|
||||
if (ret != PackageManager.INSTALL_SUCCEEDED) {
|
||||
Slog.e(TAG, "Failed to copy package");
|
||||
return ret;
|
||||
}
|
||||
|
||||
final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
|
||||
NativeLibraryHelper.Handle handle = null;
|
||||
try {
|
||||
handle = NativeLibraryHelper.Handle.create(codeFile);
|
||||
ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, libraryRoot,
|
||||
abiOverride, multiArch);
|
||||
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
|
||||
abiOverride);
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Copying native libraries failed", e);
|
||||
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
|
||||
@ -9429,18 +9432,18 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
/** New install */
|
||||
AsecInstallArgs(InstallParams params) {
|
||||
super(params.originFile, params.originStaged, params.observer, params.flags,
|
||||
super(params.origin, params.observer, params.flags,
|
||||
params.installerPackageName, params.getManifestDigest(),
|
||||
params.getUser(), null /* instruction sets */,
|
||||
params.packageAbiOverride, params.multiArch);
|
||||
params.packageAbiOverride);
|
||||
}
|
||||
|
||||
/** Existing install */
|
||||
AsecInstallArgs(String fullCodePath, String[] instructionSets,
|
||||
boolean isExternal, boolean isForwardLocked, boolean isMultiArch) {
|
||||
super(null, false, null, (isExternal ? INSTALL_EXTERNAL : 0)
|
||||
boolean isExternal, boolean isForwardLocked) {
|
||||
super(new OriginInfo(null, null, false), null, (isExternal ? INSTALL_EXTERNAL : 0)
|
||||
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
|
||||
instructionSets, null, isMultiArch);
|
||||
instructionSets, null);
|
||||
// Hackily pretend we're still looking at a full code path
|
||||
if (!fullCodePath.endsWith(RES_FILE_NAME)) {
|
||||
fullCodePath = new File(fullCodePath, RES_FILE_NAME).getAbsolutePath();
|
||||
@ -9454,21 +9457,20 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
setMountPath(subStr1);
|
||||
}
|
||||
|
||||
AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked,
|
||||
boolean isMultiArch) {
|
||||
super(null, false, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
|
||||
AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
|
||||
super(new OriginInfo(null, null, false), null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
|
||||
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
|
||||
instructionSets, null, isMultiArch);
|
||||
instructionSets, null);
|
||||
this.cid = cid;
|
||||
setMountPath(PackageHelper.getSdDir(cid));
|
||||
}
|
||||
|
||||
/** New install from existing */
|
||||
AsecInstallArgs(File originPackageFile, String cid, String[] instructionSets,
|
||||
boolean isExternal, boolean isForwardLocked, boolean isMultiArch) {
|
||||
super(originPackageFile, false, null, (isExternal ? INSTALL_EXTERNAL : 0)
|
||||
boolean isExternal, boolean isForwardLocked) {
|
||||
super(new OriginInfo(originPackageFile, null, false), null, (isExternal ? INSTALL_EXTERNAL : 0)
|
||||
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
|
||||
instructionSets, null, isMultiArch);
|
||||
instructionSets, null);
|
||||
this.cid = cid;
|
||||
}
|
||||
|
||||
@ -9496,7 +9498,13 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
|
||||
// TODO: if already staged, we only need to extract native code
|
||||
if (origin.staged) {
|
||||
Slog.d(TAG, origin.cid + " already staged; skipping copy");
|
||||
cid = origin.cid;
|
||||
setMountPath(PackageHelper.getSdDir(cid));
|
||||
return PackageManager.INSTALL_SUCCEEDED;
|
||||
}
|
||||
|
||||
if (temp) {
|
||||
createCopyFile();
|
||||
} else {
|
||||
@ -9508,7 +9516,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
final String newMountPath = imcs.copyPackageToContainer(
|
||||
originFile.getAbsolutePath(), cid, getEncryptKey(), isExternal(),
|
||||
origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternal(),
|
||||
isFwdLocked(), deriveAbiOverride(abiOverride, null /* settings */));
|
||||
|
||||
if (newMountPath != null) {
|
||||
@ -10133,8 +10141,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
deletedPackage.applicationInfo.getCodePath(),
|
||||
deletedPackage.applicationInfo.getResourcePath(),
|
||||
deletedPackage.applicationInfo.nativeLibraryRootDir,
|
||||
getAppDexInstructionSets(deletedPackage.applicationInfo),
|
||||
isMultiArch(deletedPackage.applicationInfo));
|
||||
getAppDexInstructionSets(deletedPackage.applicationInfo));
|
||||
} else {
|
||||
res.removedInfo.args = null;
|
||||
}
|
||||
@ -10920,7 +10927,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
if (deleteCodeAndResources && (outInfo != null)) {
|
||||
outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
|
||||
ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
|
||||
getAppDexInstructionSets(ps), isMultiArch(ps));
|
||||
getAppDexInstructionSets(ps));
|
||||
if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
|
||||
}
|
||||
return true;
|
||||
@ -12725,7 +12732,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
final AsecInstallArgs args = new AsecInstallArgs(cid,
|
||||
getAppDexInstructionSets(ps), isForwardLocked(ps), isMultiArch(ps));
|
||||
getAppDexInstructionSets(ps), isForwardLocked(ps));
|
||||
// The package status is changed only if the code path
|
||||
// matches between settings and the container id.
|
||||
if (ps.codePathString != null
|
||||
@ -13019,7 +13026,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
* anyway.
|
||||
*/
|
||||
if (returnCode != PackageManager.MOVE_SUCCEEDED) {
|
||||
processPendingMove(new MoveParams(null, observer, 0, packageName, null, -1, user, false),
|
||||
processPendingMove(new MoveParams(null, observer, 0, packageName, null, -1, user),
|
||||
returnCode);
|
||||
} else {
|
||||
Message msg = mHandler.obtainMessage(INIT_COPY);
|
||||
@ -13027,9 +13034,9 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
final boolean multiArch = isMultiArch(pkg.applicationInfo);
|
||||
InstallArgs srcArgs = createInstallArgsForExisting(currFlags,
|
||||
pkg.applicationInfo.getCodePath(), pkg.applicationInfo.getResourcePath(),
|
||||
pkg.applicationInfo.nativeLibraryRootDir, instructionSets, multiArch);
|
||||
pkg.applicationInfo.nativeLibraryRootDir, instructionSets);
|
||||
MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
|
||||
instructionSets, pkg.applicationInfo.uid, user, multiArch);
|
||||
instructionSets, pkg.applicationInfo.uid, user);
|
||||
msg.obj = mp;
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
@ -13107,8 +13114,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
final int abi = NativeLibraryHelper.findSupportedAbi(
|
||||
handle, Build.SUPPORTED_ABIS);
|
||||
if (abi >= 0) {
|
||||
NativeLibraryHelper.copyNativeBinariesIfNeededLI(
|
||||
handle, newNativeDir, Build.SUPPORTED_ABIS[abi]);
|
||||
NativeLibraryHelper.copyNativeBinaries(handle,
|
||||
newNativeDir, Build.SUPPORTED_ABIS[abi]);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
Slog.w(TAG, "Unable to extract native libs for package :"
|
||||
|
Reference in New Issue
Block a user