Finish removing ASEC.
Awhile back we explicitly blocked any new ASEC installs, with the expectation that we'd eventually remove the logic entirely. We've had them disabled for about a week now without incident, so let's rip out the remaining code. Test: bit FrameworksCoreTests:android.content.pm.PackageHelperTests Test: bit FrameworksCoreTests:android.content.pm.PackageManagerTests Bug: 32913676 Change-Id: I1ecc35487420731f5c4bdf03bca5751548ce51b3
This commit is contained in:
@@ -416,7 +416,7 @@ public final class Pm {
|
||||
PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
|
||||
null, null);
|
||||
params.sessionParams.setSize(
|
||||
PackageHelper.calculateInstalledSize(pkgLite, false,
|
||||
PackageHelper.calculateInstalledSize(pkgLite,
|
||||
params.sessionParams.abiOverride));
|
||||
} catch (PackageParserException | IOException e) {
|
||||
System.err.println("Error: Failed to parse APK file: " + e);
|
||||
|
||||
@@ -554,14 +554,6 @@ interface IPackageManager {
|
||||
*/
|
||||
void reconcileSecondaryDexFiles(String packageName);
|
||||
|
||||
/**
|
||||
* Update status of external media on the package manager to scan and
|
||||
* install packages installed on the external media. Like say the
|
||||
* StorageManagerService uses this to call into the package manager to update
|
||||
* status of sdcard.
|
||||
*/
|
||||
void updateExternalMediaStatus(boolean mounted, boolean reportStatus);
|
||||
|
||||
PackageCleanItem nextPackageToClean(in PackageCleanItem lastPackage);
|
||||
|
||||
int getMoveStatus(int moveId);
|
||||
|
||||
@@ -44,103 +44,11 @@ interface IStorageManager {
|
||||
* Unregisters an IStorageEventListener
|
||||
*/
|
||||
void unregisterListener(IStorageEventListener listener) = 1;
|
||||
/**
|
||||
* Returns true if a USB mass storage host is connected
|
||||
*/
|
||||
boolean isUsbMassStorageConnected() = 2;
|
||||
/**
|
||||
* Enables / disables USB mass storage. The caller should check actual
|
||||
* status of enabling/disabling USB mass storage via StorageEventListener.
|
||||
*/
|
||||
void setUsbMassStorageEnabled(boolean enable) = 3;
|
||||
/**
|
||||
* Returns true if a USB mass storage host is enabled (media is shared)
|
||||
*/
|
||||
boolean isUsbMassStorageEnabled() = 4;
|
||||
/**
|
||||
* Mount external storage at given mount point. Returns an int consistent
|
||||
* with StorageResultCode
|
||||
*/
|
||||
int mountVolume(in String mountPoint) = 5;
|
||||
/**
|
||||
* Safely unmount external storage at given mount point. The unmount is an
|
||||
* asynchronous operation. Applications should register StorageEventListener
|
||||
* for storage related status changes.
|
||||
* @param mountPoint the mount point
|
||||
* @param force whether or not to forcefully unmount it (e.g. even if programs are using this
|
||||
* data currently)
|
||||
* @param removeEncryption whether or not encryption mapping should be removed from the volume.
|
||||
* This value implies {@code force}.
|
||||
*/
|
||||
void unmountVolume(in String mountPoint, boolean force, boolean removeEncryption) = 6;
|
||||
/**
|
||||
* Format external storage given a mount point. Returns an int consistent
|
||||
* with StorageResultCode
|
||||
*/
|
||||
int formatVolume(in String mountPoint) = 7;
|
||||
/**
|
||||
* Returns an array of pids with open files on the specified path.
|
||||
*/
|
||||
int[] getStorageUsers(in String path) = 8;
|
||||
/**
|
||||
* Gets the state of a volume via its mountpoint.
|
||||
*/
|
||||
String getVolumeState(in String mountPoint) = 9;
|
||||
/*
|
||||
* Creates a secure container with the specified parameters. Returns an int
|
||||
* consistent with StorageResultCode
|
||||
*/
|
||||
int createSecureContainer(in String id, int sizeMb, in String fstype, in String key,
|
||||
int ownerUid, boolean external) = 10;
|
||||
/*
|
||||
* Finalize a container which has just been created and populated. After
|
||||
* finalization, the container is immutable. Returns an int consistent with
|
||||
* StorageResultCode
|
||||
*/
|
||||
int finalizeSecureContainer(in String id) = 11;
|
||||
/*
|
||||
* Destroy a secure container, and free up all resources associated with it.
|
||||
* NOTE: Ensure all references are released prior to deleting. Returns an
|
||||
* int consistent with StorageResultCode
|
||||
*/
|
||||
int destroySecureContainer(in String id, boolean force) = 12;
|
||||
/*
|
||||
* Mount a secure container with the specified key and owner UID. Returns an
|
||||
* int consistent with StorageResultCode
|
||||
*/
|
||||
int mountSecureContainer(in String id, in String key, int ownerUid, boolean readOnly) = 13;
|
||||
/*
|
||||
* Unount a secure container. Returns an int consistent with
|
||||
* StorageResultCode
|
||||
*/
|
||||
int unmountSecureContainer(in String id, boolean force) = 14;
|
||||
/*
|
||||
* Returns true if the specified container is mounted
|
||||
*/
|
||||
boolean isSecureContainerMounted(in String id) = 15;
|
||||
/*
|
||||
* Rename an unmounted secure container. Returns an int consistent with
|
||||
* StorageResultCode
|
||||
*/
|
||||
int renameSecureContainer(in String oldId, in String newId) = 16;
|
||||
/*
|
||||
* Returns the filesystem path of a mounted secure container.
|
||||
*/
|
||||
String getSecureContainerPath(in String id) = 17;
|
||||
/**
|
||||
* Gets an Array of currently known secure container IDs
|
||||
*/
|
||||
String[] getSecureContainerList() = 18;
|
||||
/**
|
||||
* Shuts down the StorageManagerService and gracefully unmounts all external media.
|
||||
* Invokes call back once the shutdown is complete.
|
||||
*/
|
||||
void shutdown(IStorageShutdownObserver observer) = 19;
|
||||
/**
|
||||
* Call into StorageManagerService by PackageManager to notify that its done
|
||||
* processing the media status update request.
|
||||
*/
|
||||
void finishMediaUpdate() = 20;
|
||||
/**
|
||||
* Mounts an Opaque Binary Blob (OBB) with the specified decryption key and
|
||||
* only allows the calling process's UID access to the contents.
|
||||
@@ -165,10 +73,6 @@ interface IStorageManager {
|
||||
* Gets the path to the mounted Opaque Binary Blob (OBB).
|
||||
*/
|
||||
String getMountedObbPath(in String rawPath) = 24;
|
||||
/**
|
||||
* Returns whether or not the external storage is emulated.
|
||||
*/
|
||||
boolean isExternalStorageEmulated() = 25;
|
||||
/**
|
||||
* Decrypts any encrypted volumes.
|
||||
*/
|
||||
@@ -185,14 +89,6 @@ interface IStorageManager {
|
||||
* Returns list of all mountable volumes.
|
||||
*/
|
||||
StorageVolume[] getVolumeList(int uid, in String packageName, int flags) = 29;
|
||||
/**
|
||||
* Gets the path on the filesystem for the ASEC container itself.
|
||||
*
|
||||
* @param cid ASEC container ID
|
||||
* @return path to filesystem or {@code null} if it's not found
|
||||
* @throws RemoteException
|
||||
*/
|
||||
String getSecureContainerFilesystemPath(in String cid) = 30;
|
||||
/**
|
||||
* Determines the encryption state of the volume.
|
||||
* @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible
|
||||
@@ -208,11 +104,6 @@ interface IStorageManager {
|
||||
* may only be called by the system process.
|
||||
*/
|
||||
int verifyEncryptionPassword(in String password) = 32;
|
||||
/*
|
||||
* Fix permissions in a container which has just been created and populated.
|
||||
* Returns an int consistent with StorageResultCode
|
||||
*/
|
||||
int fixPermissionsSecureContainer(in String id, int gid, in String filename) = 33;
|
||||
/**
|
||||
* Ensure that all directories along given path exist, creating parent
|
||||
* directories as needed. Validates that given path is absolute and that it
|
||||
@@ -247,7 +138,6 @@ interface IStorageManager {
|
||||
* @return contents of field
|
||||
*/
|
||||
String getField(in String field) = 39;
|
||||
int resizeSecureContainer(in String id, int sizeMb, in String key) = 40;
|
||||
/**
|
||||
* Report the time of the last maintenance operation such as fstrim.
|
||||
* @return Timestamp of the last maintenance operation, in the
|
||||
@@ -260,7 +150,6 @@ interface IStorageManager {
|
||||
* @throws RemoteException
|
||||
*/
|
||||
void runMaintenance() = 42;
|
||||
void waitForAsecScan() = 43;
|
||||
DiskInfo[] getDisks() = 44;
|
||||
VolumeInfo[] getVolumes(int flags) = 45;
|
||||
VolumeRecord[] getVolumeRecords(int flags) = 46;
|
||||
|
||||
@@ -21,12 +21,10 @@ import android.content.pm.PackageInfoLite;
|
||||
import android.content.res.ObbInfo;
|
||||
|
||||
interface IMediaContainerService {
|
||||
String copyPackageToContainer(String packagePath, String containerId, String key,
|
||||
boolean isExternal, boolean isForwardLocked, String abiOverride);
|
||||
int copyPackage(String packagePath, in IParcelFileDescriptorFactory target);
|
||||
|
||||
PackageInfoLite getMinimalPackageInfo(String packagePath, int flags, String abiOverride);
|
||||
ObbInfo getObbInfo(String filename);
|
||||
void clearDirectory(String directory);
|
||||
long calculateInstalledSize(String packagePath, boolean isForwardLocked, String abiOverride);
|
||||
long calculateInstalledSize(String packagePath, String abiOverride);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.internal.content;
|
||||
|
||||
import static android.net.TrafficStats.MB_IN_BYTES;
|
||||
import static android.os.storage.VolumeInfo.ID_PRIVATE_INTERNAL;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -27,13 +26,11 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.PackageParser.PackageLite;
|
||||
import android.os.Environment;
|
||||
import android.os.FileUtils;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.storage.IStorageManager;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.os.storage.StorageResultCode;
|
||||
import android.os.storage.StorageVolume;
|
||||
import android.os.storage.VolumeInfo;
|
||||
import android.provider.Settings;
|
||||
@@ -45,15 +42,9 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* Constants used internally between the PackageManager
|
||||
@@ -72,7 +63,6 @@ public class PackageHelper {
|
||||
public static final int RECOMMEND_FAILED_INVALID_URI = -6;
|
||||
public static final int RECOMMEND_FAILED_VERSION_DOWNGRADE = -7;
|
||||
|
||||
private static final boolean localLOGV = false;
|
||||
private static final String TAG = "PackageHelper";
|
||||
// App installation location settings values
|
||||
public static final int APP_INSTALL_AUTO = 0;
|
||||
@@ -91,259 +81,6 @@ public class PackageHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static String createSdDir(long sizeBytes, String cid, String sdEncKey, int uid,
|
||||
boolean isExternal) {
|
||||
// Round up to nearest MB, plus another MB for filesystem overhead
|
||||
final int sizeMb = (int) ((sizeBytes + MB_IN_BYTES) / MB_IN_BYTES) + 1;
|
||||
try {
|
||||
IStorageManager storageManager = getStorageManager();
|
||||
|
||||
if (localLOGV)
|
||||
Log.i(TAG, "Size of container " + sizeMb + " MB");
|
||||
|
||||
int rc = storageManager.createSecureContainer(cid, sizeMb, "ext4", sdEncKey, uid,
|
||||
isExternal);
|
||||
if (rc != StorageResultCode.OperationSucceeded) {
|
||||
Log.e(TAG, "Failed to create secure container " + cid);
|
||||
return null;
|
||||
}
|
||||
String cachePath = storageManager.getSecureContainerPath(cid);
|
||||
if (localLOGV) Log.i(TAG, "Created secure container " + cid +
|
||||
" at " + cachePath);
|
||||
return cachePath;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "StorageManagerService running?");
|
||||
}
|
||||
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 {
|
||||
IStorageManager storageManager = getStorageManager();
|
||||
int rc = storageManager.resizeSecureContainer(cid, sizeMb, sdEncKey);
|
||||
if (rc == StorageResultCode.OperationSucceeded) {
|
||||
return true;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "StorageManagerService 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 = getStorageManager().mountSecureContainer(cid, key, ownerUid, readOnly);
|
||||
if (rc != StorageResultCode.OperationSucceeded) {
|
||||
Log.i(TAG, "Failed to mount container " + cid + " rc : " + rc);
|
||||
return null;
|
||||
}
|
||||
return getStorageManager().getSecureContainerPath(cid);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "StorageManagerService running?");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean unMountSdDir(String cid) {
|
||||
try {
|
||||
int rc = getStorageManager().unmountSecureContainer(cid, true);
|
||||
if (rc != StorageResultCode.OperationSucceeded) {
|
||||
Log.e(TAG, "Failed to unmount " + cid + " with rc " + rc);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "StorageManagerService running?");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean renameSdDir(String oldId, String newId) {
|
||||
try {
|
||||
int rc = getStorageManager().renameSecureContainer(oldId, newId);
|
||||
if (rc != StorageResultCode.OperationSucceeded) {
|
||||
Log.e(TAG, "Failed to rename " + oldId + " to " +
|
||||
newId + "with rc " + rc);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
Log.i(TAG, "Failed ot rename " + oldId + " to " + newId +
|
||||
" with exception : " + e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getSdDir(String cid) {
|
||||
try {
|
||||
return getStorageManager().getSecureContainerPath(cid);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to get container path for " + cid +
|
||||
" with exception " + e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getSdFilesystem(String cid) {
|
||||
try {
|
||||
return getStorageManager().getSecureContainerFilesystemPath(cid);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to get container path for " + cid +
|
||||
" with exception " + e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean finalizeSdDir(String cid) {
|
||||
try {
|
||||
int rc = getStorageManager().finalizeSecureContainer(cid);
|
||||
if (rc != StorageResultCode.OperationSucceeded) {
|
||||
Log.i(TAG, "Failed to finalize container " + cid);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to finalize container " + cid +
|
||||
" with exception " + e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean destroySdDir(String cid) {
|
||||
try {
|
||||
if (localLOGV) Log.i(TAG, "Forcibly destroying container " + cid);
|
||||
int rc = getStorageManager().destroySecureContainer(cid, true);
|
||||
if (rc != StorageResultCode.OperationSucceeded) {
|
||||
Log.i(TAG, "Failed to destroy container " + cid);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to destroy container " + cid +
|
||||
" with exception " + e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String[] getSecureContainerList() {
|
||||
try {
|
||||
return getStorageManager().getSecureContainerList();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to get secure container list with exception" +
|
||||
e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isContainerMounted(String cid) {
|
||||
try {
|
||||
return getStorageManager().isSecureContainerMounted(cid);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to find out if container " + cid + " mounted");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract public files for the single given APK.
|
||||
*/
|
||||
public static long extractPublicFiles(File apkFile, File publicZipFile)
|
||||
throws IOException {
|
||||
final FileOutputStream fstr;
|
||||
final ZipOutputStream publicZipOutStream;
|
||||
|
||||
if (publicZipFile == null) {
|
||||
fstr = null;
|
||||
publicZipOutStream = null;
|
||||
} else {
|
||||
fstr = new FileOutputStream(publicZipFile);
|
||||
publicZipOutStream = new ZipOutputStream(fstr);
|
||||
Log.d(TAG, "Extracting " + apkFile + " to " + publicZipFile);
|
||||
}
|
||||
|
||||
long size = 0L;
|
||||
|
||||
try {
|
||||
final ZipFile privateZip = new ZipFile(apkFile.getAbsolutePath());
|
||||
try {
|
||||
// Copy manifest, resources.arsc and res directory to public zip
|
||||
for (final ZipEntry zipEntry : Collections.list(privateZip.entries())) {
|
||||
final String zipEntryName = zipEntry.getName();
|
||||
if ("AndroidManifest.xml".equals(zipEntryName)
|
||||
|| "resources.arsc".equals(zipEntryName)
|
||||
|| zipEntryName.startsWith("res/")) {
|
||||
size += zipEntry.getSize();
|
||||
if (publicZipFile != null) {
|
||||
copyZipEntry(zipEntry, privateZip, publicZipOutStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
try { privateZip.close(); } catch (IOException e) {}
|
||||
}
|
||||
|
||||
if (publicZipFile != null) {
|
||||
publicZipOutStream.finish();
|
||||
publicZipOutStream.flush();
|
||||
FileUtils.sync(fstr);
|
||||
publicZipOutStream.close();
|
||||
FileUtils.setPermissions(publicZipFile.getAbsolutePath(), FileUtils.S_IRUSR
|
||||
| FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IROTH, -1, -1);
|
||||
}
|
||||
} finally {
|
||||
IoUtils.closeQuietly(publicZipOutStream);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private static void copyZipEntry(ZipEntry zipEntry, ZipFile inZipFile,
|
||||
ZipOutputStream outZipStream) throws IOException {
|
||||
byte[] buffer = new byte[4096];
|
||||
int num;
|
||||
|
||||
ZipEntry newEntry;
|
||||
if (zipEntry.getMethod() == ZipEntry.STORED) {
|
||||
// Preserve the STORED method of the input entry.
|
||||
newEntry = new ZipEntry(zipEntry);
|
||||
} else {
|
||||
// Create a new entry so that the compressed len is recomputed.
|
||||
newEntry = new ZipEntry(zipEntry.getName());
|
||||
}
|
||||
outZipStream.putNextEntry(newEntry);
|
||||
|
||||
final InputStream data = inZipFile.getInputStream(zipEntry);
|
||||
try {
|
||||
while ((num = data.read(buffer)) > 0) {
|
||||
outZipStream.write(buffer, 0, num);
|
||||
}
|
||||
outZipStream.flush();
|
||||
} finally {
|
||||
IoUtils.closeQuietly(data);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean fixSdPermissions(String cid, int gid, String filename) {
|
||||
try {
|
||||
int rc = getStorageManager().fixPermissionsSecureContainer(cid, gid, filename);
|
||||
if (rc != StorageResultCode.OperationSucceeded) {
|
||||
Log.i(TAG, "Failed to fixperms container " + cid);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to fixperms container " + cid + " with exception " + e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A group of external dependencies used in
|
||||
* {@link #resolveInstallVolume(Context, String, int, long)}. It can be backed by real values
|
||||
@@ -638,29 +375,37 @@ public class PackageHelper {
|
||||
return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static long calculateInstalledSize(PackageLite pkg, boolean isForwardLocked,
|
||||
String abiOverride) throws IOException {
|
||||
return calculateInstalledSize(pkg, abiOverride);
|
||||
}
|
||||
|
||||
public static long calculateInstalledSize(PackageLite pkg, String abiOverride)
|
||||
throws IOException {
|
||||
NativeLibraryHelper.Handle handle = null;
|
||||
try {
|
||||
handle = NativeLibraryHelper.Handle.create(pkg);
|
||||
return calculateInstalledSize(pkg, handle, isForwardLocked, abiOverride);
|
||||
return calculateInstalledSize(pkg, handle, abiOverride);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(handle);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static long calculateInstalledSize(PackageLite pkg, boolean isForwardLocked,
|
||||
NativeLibraryHelper.Handle handle, String abiOverride) throws IOException {
|
||||
return calculateInstalledSize(pkg, handle, abiOverride);
|
||||
}
|
||||
|
||||
public static long calculateInstalledSize(PackageLite pkg, NativeLibraryHelper.Handle handle,
|
||||
boolean isForwardLocked, String abiOverride) throws IOException {
|
||||
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
|
||||
|
||||
@@ -16,11 +16,9 @@
|
||||
|
||||
package android.content.pm;
|
||||
|
||||
import static android.os.storage.VolumeInfo.STATE_MOUNTED;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.storage.IStorageManager;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.os.storage.VolumeInfo;
|
||||
import android.test.AndroidTestCase;
|
||||
@@ -36,16 +34,10 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static android.net.TrafficStats.MB_IN_BYTES;
|
||||
import static android.os.storage.VolumeInfo.STATE_MOUNTED;
|
||||
|
||||
public class PackageHelperTests extends AndroidTestCase {
|
||||
private static final boolean localLOGV = true;
|
||||
public static final String TAG = "PackageHelperTests";
|
||||
protected final String PREFIX = "android.content.pm";
|
||||
private IStorageManager mSm;
|
||||
private String fullId;
|
||||
private String fullId2;
|
||||
|
||||
private static final String sInternalVolPath = "/data";
|
||||
private static final String sAdoptedVolPath = "/mnt/expand/123";
|
||||
@@ -147,34 +139,11 @@ public class PackageHelperTests extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private IStorageManager getSm() {
|
||||
IBinder service = ServiceManager.getService("mount");
|
||||
if (service != null) {
|
||||
return IStorageManager.Stub.asInterface(service);
|
||||
} else {
|
||||
Log.e(TAG, "Can't get mount service");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void cleanupContainers() throws RemoteException {
|
||||
Log.d(TAG,"cleanUp");
|
||||
IStorageManager sm = getSm();
|
||||
String[] containers = sm.getSecureContainerList();
|
||||
for (int i = 0; i < containers.length; i++) {
|
||||
if (containers[i].startsWith(PREFIX)) {
|
||||
Log.d(TAG,"cleaing up "+containers[i]);
|
||||
sm.destroySecureContainer(containers[i], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
sStorageManager = createStorageManagerMock();
|
||||
if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
|
||||
cleanupContainers();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -182,55 +151,6 @@ public class PackageHelperTests extends AndroidTestCase {
|
||||
super.tearDown();
|
||||
sStorageManager = null;
|
||||
if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
|
||||
cleanupContainers();
|
||||
}
|
||||
|
||||
public void testMountAndPullSdCard() throws Exception {
|
||||
fullId = PREFIX;
|
||||
fullId2 = PackageHelper.createSdDir(1024 * MB_IN_BYTES, fullId, "none",
|
||||
android.os.Process.myUid(), true);
|
||||
|
||||
Log.d(TAG, "getSdDir=" + PackageHelper.getSdDir(fullId));
|
||||
PackageHelper.unMountSdDir(fullId);
|
||||
|
||||
Runnable r1 = getMountRunnable();
|
||||
Runnable r2 = getDestroyRunnable();
|
||||
Thread thread = new Thread(r1);
|
||||
Thread thread2 = new Thread(r2);
|
||||
thread2.start();
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public Runnable getMountRunnable() {
|
||||
Runnable r = new Runnable () {
|
||||
public void run () {
|
||||
try {
|
||||
Thread.sleep(5);
|
||||
String path = PackageHelper.mountSdDir(fullId, "none",
|
||||
android.os.Process.myUid());
|
||||
Log.e(TAG, "mount done " + path);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw iae;
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "mount failed", t);
|
||||
}
|
||||
}
|
||||
};
|
||||
return r;
|
||||
}
|
||||
|
||||
public Runnable getDestroyRunnable() {
|
||||
Runnable r = new Runnable () {
|
||||
public void run () {
|
||||
try {
|
||||
PackageHelper.destroySdDir(fullId);
|
||||
Log.e(TAG, "destroy done: " + fullId);
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "destroy failed", t);
|
||||
}
|
||||
}
|
||||
};
|
||||
return r;
|
||||
}
|
||||
|
||||
public void testResolveInstallVolumeInternal_SystemApp() throws IOException {
|
||||
|
||||
@@ -46,13 +46,8 @@ import android.os.FileUtils;
|
||||
import android.os.IBinder;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.StatFs;
|
||||
import android.os.SystemClock;
|
||||
import android.os.storage.IStorageManager;
|
||||
import android.os.storage.StorageListener;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.os.storage.StorageResultCode;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.SettingNotFoundException;
|
||||
import android.system.ErrnoException;
|
||||
@@ -103,8 +98,6 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
|
||||
private static final int APP_INSTALL_SDCARD = PackageHelper.APP_INSTALL_EXTERNAL;
|
||||
|
||||
private boolean mOrigState;
|
||||
|
||||
void failStr(String errMsg) {
|
||||
Log.w(TAG, "errMsg=" + errMsg);
|
||||
fail(errMsg);
|
||||
@@ -114,29 +107,6 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
failStr(e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mOrigState = checkMediaState(Environment.MEDIA_MOUNTED);
|
||||
if (!mountMedia()) {
|
||||
Log.i(TAG, "sdcard not mounted? Some of these tests might fail");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
// Restore media state.
|
||||
boolean newState = checkMediaState(Environment.MEDIA_MOUNTED);
|
||||
if (newState != mOrigState) {
|
||||
if (mOrigState) {
|
||||
mountMedia();
|
||||
} else {
|
||||
unmountMedia();
|
||||
}
|
||||
}
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
private abstract static class GenericReceiver extends BroadcastReceiver {
|
||||
private boolean doneFlag = false;
|
||||
|
||||
@@ -782,17 +752,6 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
sampleInstallFromRawResource(0, true);
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
public void testInstallSdcard() throws Exception {
|
||||
// Do not run on devices with emulated external storage.
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mountMedia();
|
||||
sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, true);
|
||||
}
|
||||
|
||||
/* ------------------------- Test replacing packages -------------- */
|
||||
class ReplaceReceiver extends GenericReceiver {
|
||||
String pkgName;
|
||||
@@ -1081,240 +1040,6 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DELETE_KEEP_DATA);
|
||||
}
|
||||
|
||||
/* sdcard mount/unmount tests ***** */
|
||||
|
||||
class SdMountReceiver extends GenericReceiver {
|
||||
String pkgNames[];
|
||||
|
||||
boolean status = true;
|
||||
|
||||
SdMountReceiver(String[] pkgNames) {
|
||||
this.pkgNames = pkgNames;
|
||||
IntentFilter filter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
|
||||
super.setFilter(filter);
|
||||
}
|
||||
|
||||
public boolean notifyNow(Intent intent) {
|
||||
Log.i(TAG, "okay 1");
|
||||
String action = intent.getAction();
|
||||
if (!Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
|
||||
return false;
|
||||
}
|
||||
String rpkgList[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
|
||||
for (String pkg : pkgNames) {
|
||||
boolean found = false;
|
||||
for (String rpkg : rpkgList) {
|
||||
if (rpkg.equals(pkg)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
status = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class SdUnMountReceiver extends GenericReceiver {
|
||||
String pkgNames[];
|
||||
|
||||
boolean status = true;
|
||||
|
||||
SdUnMountReceiver(String[] pkgNames) {
|
||||
this.pkgNames = pkgNames;
|
||||
IntentFilter filter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
|
||||
super.setFilter(filter);
|
||||
}
|
||||
|
||||
public boolean notifyNow(Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (!Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
|
||||
return false;
|
||||
}
|
||||
String rpkgList[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
|
||||
for (String pkg : pkgNames) {
|
||||
boolean found = false;
|
||||
for (String rpkg : rpkgList) {
|
||||
if (rpkg.equals(pkg)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
status = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
IStorageManager getSm() {
|
||||
IBinder service = ServiceManager.getService("mount");
|
||||
if (service != null) {
|
||||
return IStorageManager.Stub.asInterface(service);
|
||||
} else {
|
||||
Log.e(TAG, "Can't get storagemanager service");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean checkMediaState(String desired) {
|
||||
String actual = Environment.getExternalStorageState();
|
||||
if (desired.equals(actual)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean mountMedia() {
|
||||
// We can't mount emulated storage.
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (checkMediaState(Environment.MEDIA_MOUNTED)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String path = Environment.getExternalStorageDirectory().toString();
|
||||
StorageListener observer = new StorageListener(Environment.MEDIA_MOUNTED);
|
||||
StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
|
||||
sm.registerListener(observer);
|
||||
try {
|
||||
// Wait on observer
|
||||
synchronized (observer) {
|
||||
int ret = getSm().mountVolume(path);
|
||||
if (ret != StorageResultCode.OperationSucceeded) {
|
||||
throw new Exception("Could not mount the media");
|
||||
}
|
||||
long waitTime = 0;
|
||||
while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
|
||||
observer.wait(WAIT_TIME_INCR);
|
||||
waitTime += WAIT_TIME_INCR;
|
||||
}
|
||||
if (!observer.isDone()) {
|
||||
throw new Exception("Timed out waiting for unmount media notification");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception : " + e);
|
||||
return false;
|
||||
} finally {
|
||||
sm.unregisterListener(observer);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean unmountMedia() {
|
||||
// We can't unmount emulated storage.
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (checkMediaState(Environment.MEDIA_UNMOUNTED)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String path = Environment.getExternalStorageDirectory().getPath();
|
||||
StorageListener observer = new StorageListener(Environment.MEDIA_UNMOUNTED);
|
||||
StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
|
||||
sm.registerListener(observer);
|
||||
try {
|
||||
// Wait on observer
|
||||
synchronized (observer) {
|
||||
getSm().unmountVolume(path, true, false);
|
||||
long waitTime = 0;
|
||||
while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
|
||||
observer.wait(WAIT_TIME_INCR);
|
||||
waitTime += WAIT_TIME_INCR;
|
||||
}
|
||||
if (!observer.isDone()) {
|
||||
throw new Exception("Timed out waiting for unmount media notification");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception : " + e);
|
||||
return false;
|
||||
} finally {
|
||||
sm.unregisterListener(observer);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mountFromRawResource() throws Exception {
|
||||
// Install pkg on sdcard
|
||||
InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, false);
|
||||
if (localLOGV) Log.i(TAG, "Installed pkg on sdcard");
|
||||
boolean origState = checkMediaState(Environment.MEDIA_MOUNTED);
|
||||
boolean registeredReceiver = false;
|
||||
SdMountReceiver receiver = new SdMountReceiver(new String[]{ip.pkg.packageName});
|
||||
try {
|
||||
if (localLOGV) Log.i(TAG, "Unmounting media");
|
||||
// Unmount media
|
||||
assertTrue(unmountMedia());
|
||||
if (localLOGV) Log.i(TAG, "Unmounted media");
|
||||
// Register receiver here
|
||||
PackageManager pm = getPm();
|
||||
mContext.registerReceiver(receiver, receiver.filter);
|
||||
registeredReceiver = true;
|
||||
|
||||
// Wait on receiver
|
||||
synchronized (receiver) {
|
||||
if (localLOGV) Log.i(TAG, "Mounting media");
|
||||
// Mount media again
|
||||
assertTrue(mountMedia());
|
||||
if (localLOGV) Log.i(TAG, "Mounted media");
|
||||
if (localLOGV) Log.i(TAG, "Waiting for notification");
|
||||
long waitTime = 0;
|
||||
// Verify we received the broadcast
|
||||
waitTime = 0;
|
||||
while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
|
||||
receiver.wait(WAIT_TIME_INCR);
|
||||
waitTime += WAIT_TIME_INCR;
|
||||
}
|
||||
if(!receiver.isDone()) {
|
||||
failStr("Timed out waiting for EXTERNAL_APPLICATIONS notification");
|
||||
}
|
||||
return receiver.received;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
failStr(e);
|
||||
return false;
|
||||
} finally {
|
||||
if (registeredReceiver) {
|
||||
mContext.unregisterReceiver(receiver);
|
||||
}
|
||||
// Restore original media state
|
||||
if (origState) {
|
||||
mountMedia();
|
||||
} else {
|
||||
unmountMedia();
|
||||
}
|
||||
if (localLOGV) Log.i(TAG, "Cleaning up install");
|
||||
cleanUpInstall(ip);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Install package on sdcard. Unmount and then mount the media.
|
||||
* (Use PackageManagerService private api for now)
|
||||
* Make sure the installed package is available.
|
||||
*/
|
||||
@LargeTest
|
||||
public void testMountSdNormalInternal() throws Exception {
|
||||
// Do not run on devices with emulated external storage.
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertTrue(mountFromRawResource());
|
||||
}
|
||||
|
||||
void cleanUpInstall(InstallParams ip) throws Exception {
|
||||
if (ip == null) {
|
||||
return;
|
||||
@@ -1713,64 +1438,6 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that an install error code is returned when media is unmounted
|
||||
* and package installed on sdcard via package manager flag.
|
||||
*/
|
||||
@LargeTest
|
||||
public void testInstallSdcardUnmount() throws Exception {
|
||||
// Do not run on devices with emulated external storage.
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean origState = checkMediaState(Environment.MEDIA_MOUNTED);
|
||||
try {
|
||||
// Unmount sdcard
|
||||
assertTrue(unmountMedia());
|
||||
// Try to install and make sure an error code is returned.
|
||||
installFromRawResource("install.apk", R.raw.install,
|
||||
PackageManager.INSTALL_EXTERNAL, false,
|
||||
true, PackageInstaller.STATUS_FAILURE_STORAGE,
|
||||
PackageInfo.INSTALL_LOCATION_AUTO);
|
||||
} finally {
|
||||
// Restore original media state
|
||||
if (origState) {
|
||||
mountMedia();
|
||||
} else {
|
||||
unmountMedia();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmount sdcard. Try installing an app with manifest option to install
|
||||
* on sdcard. Make sure it gets installed on internal flash.
|
||||
*/
|
||||
@LargeTest
|
||||
public void testInstallManifestSdcardUnmount() throws Exception {
|
||||
// Do not run on devices with emulated external storage.
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean origState = checkMediaState(Environment.MEDIA_MOUNTED);
|
||||
try {
|
||||
// Unmount sdcard
|
||||
assertTrue(unmountMedia());
|
||||
InstallParams ip = new InstallParams("install.apk", R.raw.install_loc_sdcard);
|
||||
installFromRawResource(ip, 0, true, false, -1,
|
||||
PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
|
||||
} finally {
|
||||
// Restore original media state
|
||||
if (origState) {
|
||||
mountMedia();
|
||||
} else {
|
||||
unmountMedia();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*---------- Recommended install location tests ----*/
|
||||
/*
|
||||
* PrecedenceSuffixes:
|
||||
@@ -2526,133 +2193,6 @@ public class PackageManagerTests extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that permissions are properly declared.
|
||||
*/
|
||||
@LargeTest
|
||||
public void testInstallOnSdPermissionsUnmount() throws Exception {
|
||||
InstallParams ip = null;
|
||||
boolean origMediaState = checkMediaState(Environment.MEDIA_MOUNTED);
|
||||
try {
|
||||
// **: Upon installing a package, are its declared permissions published?
|
||||
int iFlags = PackageManager.INSTALL_INTERNAL;
|
||||
int iApk = R.raw.install_decl_perm;
|
||||
ip = installFromRawResource("install.apk", iApk,
|
||||
iFlags, false,
|
||||
false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
|
||||
assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
|
||||
assertPermissions(BASE_PERMISSIONS_DEFINED);
|
||||
// Unmount media here
|
||||
assertTrue(unmountMedia());
|
||||
// Mount media again
|
||||
mountMedia();
|
||||
//Check permissions now
|
||||
assertPermissions(BASE_PERMISSIONS_DEFINED);
|
||||
} finally {
|
||||
if (ip != null) {
|
||||
cleanUpInstall(ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This test creates a stale container via StorageManagerService and then installs
|
||||
* a package and verifies that the stale container is cleaned up and install
|
||||
* is successful.
|
||||
* Please note that this test is very closely tied to the framework's
|
||||
* naming convention for secure containers.
|
||||
*/
|
||||
@LargeTest
|
||||
public void testInstallSdcardStaleContainer() throws Exception {
|
||||
// Do not run on devices with emulated external storage.
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean origMediaState = checkMediaState(Environment.MEDIA_MOUNTED);
|
||||
try {
|
||||
// Mount media first
|
||||
mountMedia();
|
||||
String outFileName = "install.apk";
|
||||
int rawResId = R.raw.install;
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
File filesDir = mContext.getFilesDir();
|
||||
File outFile = new File(filesDir, outFileName);
|
||||
Uri packageURI = getInstallablePackage(rawResId, outFile);
|
||||
PackageParser.Package pkg = parsePackage(packageURI);
|
||||
assertNotNull(pkg);
|
||||
// Install an app on sdcard.
|
||||
installFromRawResource(outFileName, rawResId,
|
||||
PackageManager.INSTALL_EXTERNAL, false,
|
||||
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
// Unmount sdcard
|
||||
unmountMedia();
|
||||
// Delete the app on sdcard to leave a stale container on sdcard.
|
||||
GenericReceiver receiver = new DeleteReceiver(pkg.packageName);
|
||||
assertTrue(invokeDeletePackage(pkg.packageName, 0, receiver));
|
||||
mountMedia();
|
||||
// Reinstall the app and make sure it gets installed.
|
||||
installFromRawResource(outFileName, rawResId,
|
||||
PackageManager.INSTALL_EXTERNAL, true,
|
||||
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
} catch (Exception e) {
|
||||
failStr(e.getMessage());
|
||||
} finally {
|
||||
if (origMediaState) {
|
||||
mountMedia();
|
||||
} else {
|
||||
unmountMedia();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* This test installs an application on sdcard and unmounts media.
|
||||
* The app is then re-installed on internal storage. The sdcard is mounted
|
||||
* and verified that the re-installation on internal storage takes precedence.
|
||||
*/
|
||||
@LargeTest
|
||||
public void testInstallSdcardStaleContainerReinstall() throws Exception {
|
||||
// Do not run on devices with emulated external storage.
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean origMediaState = checkMediaState(Environment.MEDIA_MOUNTED);
|
||||
try {
|
||||
// Mount media first
|
||||
mountMedia();
|
||||
String outFileName = "install.apk";
|
||||
int rawResId = R.raw.install;
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
File filesDir = mContext.getFilesDir();
|
||||
File outFile = new File(filesDir, outFileName);
|
||||
Uri packageURI = getInstallablePackage(rawResId, outFile);
|
||||
PackageParser.Package pkg = parsePackage(packageURI);
|
||||
assertNotNull(pkg);
|
||||
// Install an app on sdcard.
|
||||
installFromRawResource(outFileName, rawResId,
|
||||
PackageManager.INSTALL_EXTERNAL, false,
|
||||
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
// Unmount sdcard
|
||||
unmountMedia();
|
||||
// Reinstall the app and make sure it gets installed on internal storage.
|
||||
installFromRawResource(outFileName, rawResId,
|
||||
PackageManager.INSTALL_REPLACE_EXISTING, false,
|
||||
false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
|
||||
mountMedia();
|
||||
// Verify that the app installed is on internal storage.
|
||||
assertInstall(pkg, 0, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
|
||||
} catch (Exception e) {
|
||||
failStr(e.getMessage());
|
||||
} finally {
|
||||
if (origMediaState) {
|
||||
mountMedia();
|
||||
} else {
|
||||
unmountMedia();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following series of tests are related to upgrading apps with
|
||||
* different certificates.
|
||||
|
||||
@@ -1,756 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.os.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
public class AsecTests extends AndroidTestCase {
|
||||
private static final String SECURE_CONTAINER_PREFIX = "com.android.unittests.AsecTests.";
|
||||
private static final boolean localLOGV = true;
|
||||
public static final String TAG="AsecTests";
|
||||
|
||||
private static final String FS_FAT = "fat";
|
||||
private static final String FS_EXT4 = "ext4";
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
|
||||
cleanupContainers();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
|
||||
cleanupContainers();
|
||||
}
|
||||
|
||||
private void cleanupContainers() throws RemoteException {
|
||||
IStorageManager sm = getSm();
|
||||
String[] containers = sm.getSecureContainerList();
|
||||
|
||||
for (int i = 0; i < containers.length; i++) {
|
||||
if (containers[i].startsWith(SECURE_CONTAINER_PREFIX)) {
|
||||
if (localLOGV)
|
||||
Log.i(TAG, "Cleaning: " + containers[i]);
|
||||
sm.destroySecureContainer(containers[i], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containerExists(String localId) throws RemoteException {
|
||||
IStorageManager sm = getSm();
|
||||
String[] containers = sm.getSecureContainerList();
|
||||
String fullId = SECURE_CONTAINER_PREFIX + localId;
|
||||
|
||||
for (int i = 0; i < containers.length; i++) {
|
||||
if (containers[i].equals(fullId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int createContainer(String localId, int size, String key, String filesystem,
|
||||
boolean isExternal) throws Exception {
|
||||
assertTrue("Media should be mounted", isMediaMounted());
|
||||
String fullId = SECURE_CONTAINER_PREFIX + localId;
|
||||
|
||||
IStorageManager sm = getSm();
|
||||
return sm.createSecureContainer(fullId, size, filesystem, key, android.os.Process.myUid(),
|
||||
isExternal);
|
||||
}
|
||||
|
||||
private int mountContainer(String localId, String key) throws Exception {
|
||||
assertTrue("Media should be mounted", isMediaMounted());
|
||||
String fullId = SECURE_CONTAINER_PREFIX + localId;
|
||||
|
||||
IStorageManager sm = getSm();
|
||||
return sm.mountSecureContainer(fullId, key, android.os.Process.myUid(), true);
|
||||
}
|
||||
|
||||
private int renameContainer(String localId1, String localId2) throws Exception {
|
||||
assertTrue("Media should be mounted", isMediaMounted());
|
||||
String fullId1 = SECURE_CONTAINER_PREFIX + localId1;
|
||||
String fullId2 = SECURE_CONTAINER_PREFIX + localId2;
|
||||
|
||||
IStorageManager sm = getSm();
|
||||
return sm.renameSecureContainer(fullId1, fullId2);
|
||||
}
|
||||
|
||||
private int unmountContainer(String localId, boolean force) throws Exception {
|
||||
assertTrue("Media should be mounted", isMediaMounted());
|
||||
String fullId = SECURE_CONTAINER_PREFIX + localId;
|
||||
|
||||
IStorageManager sm = getSm();
|
||||
return sm.unmountSecureContainer(fullId, force);
|
||||
}
|
||||
|
||||
private int destroyContainer(String localId, boolean force) throws Exception {
|
||||
assertTrue("Media should be mounted", isMediaMounted());
|
||||
String fullId = SECURE_CONTAINER_PREFIX + localId;
|
||||
|
||||
IStorageManager sm = getSm();
|
||||
return sm.destroySecureContainer(fullId, force);
|
||||
}
|
||||
|
||||
private boolean isContainerMounted(String localId) throws Exception {
|
||||
assertTrue("Media should be mounted", isMediaMounted());
|
||||
String fullId = SECURE_CONTAINER_PREFIX + localId;
|
||||
|
||||
IStorageManager sm = getSm();
|
||||
return sm.isSecureContainerMounted(fullId);
|
||||
}
|
||||
|
||||
private IStorageManager getSm() {
|
||||
IBinder service = ServiceManager.getService("mount");
|
||||
if (service != null) {
|
||||
return IStorageManager.Stub.asInterface(service);
|
||||
} else {
|
||||
Log.e(TAG, "Can't get storagemanager service");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isMediaMounted() throws Exception {
|
||||
String mPath = Environment.getExternalStorageDirectory().toString();
|
||||
String state = getSm().getVolumeState(mPath);
|
||||
return Environment.MEDIA_MOUNTED.equals(state);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CREATE
|
||||
*/
|
||||
|
||||
public void test_Fat_External_Create_Success() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateContainer", 4, "none", FS_FAT, true));
|
||||
assertTrue(containerExists("testCreateContainer"));
|
||||
}
|
||||
|
||||
public void test_Ext4_External_Create_Success() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateContainer", 4, "none", FS_EXT4, true));
|
||||
assertTrue(containerExists("testCreateContainer"));
|
||||
}
|
||||
|
||||
public void test_Fat_Internal_Create_Success() throws Exception {
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateContainer", 4, "none", FS_FAT, false));
|
||||
assertTrue(containerExists("testCreateContainer"));
|
||||
}
|
||||
|
||||
public void test_Ext4_Internal_Create_Success() throws Exception {
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateContainer", 4, "none", FS_EXT4, false));
|
||||
assertTrue(containerExists("testCreateContainer"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CREATE MIN SIZE
|
||||
*/
|
||||
|
||||
public void test_Fat_External_CreateMinSize_Success() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateContainer", 1, "none", FS_FAT, true));
|
||||
assertTrue(containerExists("testCreateContainer"));
|
||||
}
|
||||
|
||||
public void test_Ext4_External_CreateMinSize_Success() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateContainer", 1, "none", FS_EXT4, true));
|
||||
assertTrue(containerExists("testCreateContainer"));
|
||||
}
|
||||
|
||||
public void test_Fat_Internal_CreateMinSize_Success() throws Exception {
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateContainer", 1, "none", FS_FAT, false));
|
||||
assertTrue(containerExists("testCreateContainer"));
|
||||
}
|
||||
|
||||
public void test_Ext4_Internal_CreateMinSize_Success() throws Exception {
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateContainer", 1, "none", FS_EXT4, false));
|
||||
assertTrue(containerExists("testCreateContainer"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CREATE ZERO SIZE - FAIL CASE
|
||||
*/
|
||||
|
||||
public void test_Fat_External_CreateZeroSize_Failure() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedInternalError,
|
||||
createContainer("testCreateZeroContainer", 0, "none", FS_FAT, true));
|
||||
}
|
||||
|
||||
public void test_Ext4_External_CreateZeroSize_Failure() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedInternalError,
|
||||
createContainer("testCreateZeroContainer", 0, "none", FS_EXT4, true));
|
||||
}
|
||||
|
||||
public void test_Fat_Internal_CreateZeroSize_Failure() throws Exception {
|
||||
assertEquals(StorageResultCode.OperationFailedInternalError,
|
||||
createContainer("testCreateZeroContainer", 0, "none", FS_FAT, false));
|
||||
}
|
||||
|
||||
public void test_Ext4_Internal_CreateZeroSize_Failure() throws Exception {
|
||||
assertEquals(StorageResultCode.OperationFailedInternalError,
|
||||
createContainer("testCreateZeroContainer", 0, "none", FS_EXT4, false));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CREATE DUPLICATE - FAIL CASE
|
||||
*/
|
||||
|
||||
public void test_Fat_External_CreateDuplicate_Failure() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateDupContainer", 4, "none", FS_FAT, true));
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedInternalError,
|
||||
createContainer("testCreateDupContainer", 4, "none", FS_FAT, true));
|
||||
}
|
||||
|
||||
public void test_Ext4_External_CreateDuplicate_Failure() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateDupContainer", 4, "none", FS_EXT4, true));
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedInternalError,
|
||||
createContainer("testCreateDupContainer", 4, "none", FS_EXT4, true));
|
||||
}
|
||||
|
||||
public void test_Fat_Internal_CreateDuplicate_Failure() throws Exception {
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateDupContainer", 4, "none", FS_FAT, false));
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedInternalError,
|
||||
createContainer("testCreateDupContainer", 4, "none", FS_FAT, false));
|
||||
}
|
||||
|
||||
public void test_Ext4_Internal_CreateDuplicate_Failure() throws Exception {
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testCreateDupContainer", 4, "none", FS_EXT4, false));
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedInternalError,
|
||||
createContainer("testCreateDupContainer", 4, "none", FS_EXT4, false));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DESTROY
|
||||
*/
|
||||
|
||||
public void test_Fat_External_Destroy_Success() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testDestroyContainer", 4, "none", FS_FAT, true));
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
destroyContainer("testDestroyContainer", false));
|
||||
}
|
||||
|
||||
public void test_Ext4_External_Destroy_Success() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testDestroyContainer", 4, "none", FS_EXT4, true));
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
destroyContainer("testDestroyContainer", false));
|
||||
}
|
||||
|
||||
public void test_Fat_Internal_Destroy_Success() throws Exception {
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testDestroyContainer", 4, "none", FS_FAT, false));
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
destroyContainer("testDestroyContainer", false));
|
||||
}
|
||||
|
||||
public void test_Ext4_Internal_Destroy_Success() throws Exception {
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testDestroyContainer", 4, "none", FS_EXT4, false));
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
destroyContainer("testDestroyContainer", false));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MOUNT
|
||||
*/
|
||||
|
||||
public void test_Fat_External_Mount() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testMountContainer", 4, "none", FS_FAT, true));
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
unmountContainer("testMountContainer", false));
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
mountContainer("testMountContainer", "none"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MOUNT BAD KEY - FAIL CASE
|
||||
*/
|
||||
|
||||
public void test_Fat_External_MountBadKey_Failure() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testMountBadKey", 4, "00000000000000000000000000000000", FS_FAT,
|
||||
true));
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
unmountContainer("testMountBadKey", false));
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedInternalError,
|
||||
mountContainer("testMountContainer", "000000000000000000000000000000001"));
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedInternalError,
|
||||
mountContainer("testMountContainer", "none"));
|
||||
}
|
||||
|
||||
|
||||
public void test_Fat_External_UnmountBusy_Success() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
IStorageManager sm = getSm();
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testUnmountBusyContainer", 4, "none", FS_FAT, true));
|
||||
|
||||
String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX
|
||||
+ "testUnmountBusyContainer");
|
||||
|
||||
File f = new File(path, "reference");
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedStorageBusy,
|
||||
unmountContainer("testUnmountBusyContainer", false));
|
||||
|
||||
fos.close();
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
unmountContainer("testUnmountBusyContainer", false));
|
||||
}
|
||||
|
||||
public void test_Fat_External_DestroyBusy() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
IStorageManager sm = getSm();
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testDestroyBusyContainer", 4, "none", FS_FAT, true));
|
||||
|
||||
String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX
|
||||
+ "testDestroyBusyContainer");
|
||||
|
||||
File f = new File(path, "reference");
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedStorageBusy,
|
||||
destroyContainer("testDestroyBusyContainer", false));
|
||||
|
||||
fos.close();
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
destroyContainer("testDestroyBusyContainer", false));
|
||||
}
|
||||
|
||||
public void test_Fat_External_Rename_Success() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testRenameContainer.1", 4, "none", FS_FAT, true));
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
unmountContainer("testRenameContainer.1", false));
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
renameContainer("testRenameContainer.1", "testRenameContainer.2"));
|
||||
|
||||
assertFalse(containerExists("testRenameContainer.1"));
|
||||
assertTrue(containerExists("testRenameContainer.2"));
|
||||
}
|
||||
|
||||
public void test_Fat_External_RenameSrcMounted_Failure() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testRenameContainer.1", 4, "none", FS_FAT, true));
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedStorageMounted,
|
||||
renameContainer("testRenameContainer.1", "testRenameContainer.2"));
|
||||
}
|
||||
|
||||
public void test_Fat_External_RenameDstMounted_Failure() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testRenameContainer.1", 4, "none", FS_FAT, true));
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
unmountContainer("testRenameContainer.1", false));
|
||||
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testRenameContainer.2", 4, "none", FS_FAT, true));
|
||||
|
||||
assertEquals(StorageResultCode.OperationFailedStorageMounted,
|
||||
renameContainer("testRenameContainer.1", "testRenameContainer.2"));
|
||||
}
|
||||
|
||||
public void test_Fat_External_Size_Success() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
IStorageManager sm = getSm();
|
||||
assertEquals(StorageResultCode.OperationSucceeded,
|
||||
createContainer("testContainerSize", 1, "none", FS_FAT, true));
|
||||
String path = sm.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testContainerSize");
|
||||
|
||||
byte[] buf = new byte[4096];
|
||||
File f = new File(path, "reference");
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
for (int i = 0; i < (1024 * 1024); i += buf.length) {
|
||||
fos.write(buf);
|
||||
}
|
||||
fos.close();
|
||||
}
|
||||
|
||||
public void testGetSecureContainerPath_NonExistPath_Failure() throws Exception {
|
||||
IStorageManager sm = getSm();
|
||||
assertNull("Getting the path for an invalid container should return null",
|
||||
sm.getSecureContainerPath("jparks.broke.it"));
|
||||
}
|
||||
|
||||
/*------------ Tests for unmounting volume ---*/
|
||||
public final long MAX_WAIT_TIME=120*1000;
|
||||
public final long WAIT_TIME_INCR=20*1000;
|
||||
|
||||
boolean getMediaState() throws Exception {
|
||||
String mPath = Environment.getExternalStorageDirectory().toString();
|
||||
String state = getSm().getVolumeState(mPath);
|
||||
return Environment.MEDIA_MOUNTED.equals(state);
|
||||
}
|
||||
|
||||
boolean mountMedia() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getMediaState()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String mPath = Environment.getExternalStorageDirectory().toString();
|
||||
int ret = getSm().mountVolume(mPath);
|
||||
return ret == StorageResultCode.OperationSucceeded;
|
||||
}
|
||||
|
||||
class StorageListener extends StorageEventListener {
|
||||
String oldState;
|
||||
String newState;
|
||||
String path;
|
||||
private boolean doneFlag = false;
|
||||
|
||||
public void action() {
|
||||
synchronized (this) {
|
||||
doneFlag = true;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return doneFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStorageStateChanged(String path, String oldState, String newState) {
|
||||
if (localLOGV) Log.i(TAG, "Storage state changed from " + oldState + " to " + newState);
|
||||
this.oldState = oldState;
|
||||
this.newState = newState;
|
||||
this.path = path;
|
||||
action();
|
||||
}
|
||||
}
|
||||
|
||||
private void unmountMedia() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getMediaState()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String path = Environment.getExternalStorageDirectory().toString();
|
||||
StorageListener observer = new StorageListener();
|
||||
StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
|
||||
sm.registerListener(observer);
|
||||
try {
|
||||
// Wait on observer
|
||||
synchronized(observer) {
|
||||
getSm().unmountVolume(path, false, false);
|
||||
long waitTime = 0;
|
||||
while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
|
||||
observer.wait(WAIT_TIME_INCR);
|
||||
waitTime += WAIT_TIME_INCR;
|
||||
}
|
||||
if(!observer.isDone()) {
|
||||
fail("Timed out waiting for packageInstalled callback");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
sm.unregisterListener(observer);
|
||||
}
|
||||
}
|
||||
|
||||
public void testUnmount() throws Exception {
|
||||
boolean oldStatus = getMediaState();
|
||||
Log.i(TAG, "oldStatus="+oldStatus);
|
||||
try {
|
||||
// Mount media firsts
|
||||
if (!getMediaState()) {
|
||||
mountMedia();
|
||||
}
|
||||
unmountMedia();
|
||||
} finally {
|
||||
// Restore old status
|
||||
boolean currStatus = getMediaState();
|
||||
if (oldStatus != currStatus) {
|
||||
if (oldStatus) {
|
||||
// Mount media
|
||||
mountMedia();
|
||||
} else {
|
||||
unmountMedia();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MultipleStorageLis extends StorageListener {
|
||||
int count = 0;
|
||||
public void onStorageStateChanged(String path, String oldState, String newState) {
|
||||
count++;
|
||||
super.action();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This test invokes unmount multiple time and expects the call back
|
||||
* to be invoked just once.
|
||||
*/
|
||||
public void testUnmountMultiple() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean oldStatus = getMediaState();
|
||||
StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
|
||||
MultipleStorageLis observer = new MultipleStorageLis();
|
||||
try {
|
||||
// Mount media firsts
|
||||
if (!getMediaState()) {
|
||||
mountMedia();
|
||||
}
|
||||
String path = Environment.getExternalStorageDirectory().toString();
|
||||
sm.registerListener(observer);
|
||||
// Wait on observer
|
||||
synchronized(observer) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
getSm().unmountVolume(path, false, false);
|
||||
}
|
||||
long waitTime = 0;
|
||||
while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
|
||||
observer.wait(WAIT_TIME_INCR);
|
||||
waitTime += WAIT_TIME_INCR;
|
||||
}
|
||||
if(!observer.isDone()) {
|
||||
fail("Timed out waiting for packageInstalled callback");
|
||||
}
|
||||
}
|
||||
assertEquals(observer.count, 1);
|
||||
} finally {
|
||||
sm.unregisterListener(observer);
|
||||
// Restore old status
|
||||
boolean currStatus = getMediaState();
|
||||
if (oldStatus != currStatus) {
|
||||
if (oldStatus) {
|
||||
// Mount media
|
||||
mountMedia();
|
||||
} else {
|
||||
unmountMedia();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ShutdownObserver extends IStorageShutdownObserver.Stub{
|
||||
private boolean doneFlag = false;
|
||||
int statusCode;
|
||||
|
||||
public void action() {
|
||||
synchronized (this) {
|
||||
doneFlag = true;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return doneFlag;
|
||||
}
|
||||
public void onShutDownComplete(int statusCode) throws RemoteException {
|
||||
this.statusCode = statusCode;
|
||||
action();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void invokeShutdown() throws Exception {
|
||||
IStorageManager sm = getSm();
|
||||
ShutdownObserver observer = new ShutdownObserver();
|
||||
synchronized (observer) {
|
||||
sm.shutdown(observer);
|
||||
}
|
||||
}
|
||||
|
||||
public void testShutdown() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean oldStatus = getMediaState();
|
||||
try {
|
||||
// Mount media firsts
|
||||
if (!getMediaState()) {
|
||||
mountMedia();
|
||||
}
|
||||
invokeShutdown();
|
||||
} finally {
|
||||
// Restore old status
|
||||
boolean currStatus = getMediaState();
|
||||
if (oldStatus != currStatus) {
|
||||
if (oldStatus) {
|
||||
// Mount media
|
||||
mountMedia();
|
||||
} else {
|
||||
unmountMedia();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This test invokes unmount multiple time and expects the call back
|
||||
* to be invoked just once.
|
||||
*/
|
||||
public void testShutdownMultiple() throws Exception {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean oldStatus = getMediaState();
|
||||
try {
|
||||
// Mount media firsts
|
||||
if (!getMediaState()) {
|
||||
mountMedia();
|
||||
}
|
||||
IStorageManager sm = getSm();
|
||||
ShutdownObserver observer = new ShutdownObserver();
|
||||
synchronized (observer) {
|
||||
sm.shutdown(observer);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
sm.shutdown(null);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Restore old status
|
||||
boolean currStatus = getMediaState();
|
||||
if (oldStatus != currStatus) {
|
||||
if (oldStatus) {
|
||||
// Mount media
|
||||
mountMedia();
|
||||
} else {
|
||||
unmountMedia();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.defcontainer;
|
||||
|
||||
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -31,21 +29,15 @@ import android.content.pm.PackageParser.PackageParserException;
|
||||
import android.content.res.ObbInfo;
|
||||
import android.content.res.ObbScanner;
|
||||
import android.os.Binder;
|
||||
import android.os.Environment;
|
||||
import android.os.Environment.UserEnvironment;
|
||||
import android.os.FileUtils;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.StructStatVfs;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.app.IMediaContainerService;
|
||||
import com.android.internal.content.NativeLibraryHelper;
|
||||
import com.android.internal.content.PackageHelper;
|
||||
import com.android.internal.os.IParcelFileDescriptorFactory;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
@@ -71,51 +63,6 @@ public class DefaultContainerService extends IntentService {
|
||||
// TODO: migrate native code unpacking to always be a derivative work
|
||||
|
||||
private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() {
|
||||
/**
|
||||
* Creates a new container and copies package there.
|
||||
*
|
||||
* @param packagePath absolute path to the package to be copied. Can be
|
||||
* a single monolithic APK file or a cluster directory
|
||||
* containing one or more APKs.
|
||||
* @param containerId the id of the secure container that should be used
|
||||
* for creating a secure container into which the resource
|
||||
* will be copied.
|
||||
* @param key Refers to key used for encrypting the secure container
|
||||
* @return Returns the new cache path where the resource has been copied
|
||||
* into
|
||||
*/
|
||||
@Override
|
||||
public String copyPackageToContainer(String packagePath, String containerId, String key,
|
||||
boolean isExternal, boolean isForwardLocked, String abiOverride) {
|
||||
if (packagePath == null || containerId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isExternal) {
|
||||
// Make sure the sdcard is mounted.
|
||||
String status = Environment.getExternalStorageState();
|
||||
if (!status.equals(Environment.MEDIA_MOUNTED)) {
|
||||
Slog.w(TAG, "Make sure sdcard is mounted.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
PackageLite pkg = null;
|
||||
NativeLibraryHelper.Handle handle = null;
|
||||
try {
|
||||
final File packageFile = new File(packagePath);
|
||||
pkg = PackageParser.parsePackageLite(packageFile, 0);
|
||||
handle = NativeLibraryHelper.Handle.create(pkg);
|
||||
return copyPackageToContainerInner(pkg, handle, containerId, key, isExternal,
|
||||
isForwardLocked, abiOverride);
|
||||
} catch (PackageParserException | IOException e) {
|
||||
Slog.w(TAG, "Failed to copy package at " + packagePath, e);
|
||||
return null;
|
||||
} finally {
|
||||
IoUtils.closeQuietly(handle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy package to the target location.
|
||||
*
|
||||
@@ -153,7 +100,6 @@ public class DefaultContainerService extends IntentService {
|
||||
public PackageInfoLite getMinimalPackageInfo(String packagePath, int flags,
|
||||
String abiOverride) {
|
||||
final Context context = DefaultContainerService.this;
|
||||
final boolean isForwardLocked = (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
|
||||
|
||||
PackageInfoLite ret = new PackageInfoLite();
|
||||
if (packagePath == null) {
|
||||
@@ -167,7 +113,7 @@ public class DefaultContainerService extends IntentService {
|
||||
final long sizeBytes;
|
||||
try {
|
||||
pkg = PackageParser.parsePackageLite(packageFile, 0);
|
||||
sizeBytes = PackageHelper.calculateInstalledSize(pkg, isForwardLocked, abiOverride);
|
||||
sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);
|
||||
} catch (PackageParserException | IOException e) {
|
||||
Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
|
||||
|
||||
@@ -230,13 +176,13 @@ public class DefaultContainerService extends IntentService {
|
||||
* containing one or more APKs.
|
||||
*/
|
||||
@Override
|
||||
public long calculateInstalledSize(String packagePath, boolean isForwardLocked,
|
||||
String abiOverride) throws RemoteException {
|
||||
public long calculateInstalledSize(String packagePath, String abiOverride)
|
||||
throws RemoteException {
|
||||
final File packageFile = new File(packagePath);
|
||||
final PackageParser.PackageLite pkg;
|
||||
try {
|
||||
pkg = PackageParser.parsePackageLite(packageFile, 0);
|
||||
return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, abiOverride);
|
||||
return PackageHelper.calculateInstalledSize(pkg, abiOverride);
|
||||
} catch (PackageParserException | IOException e) {
|
||||
Slog.w(TAG, "Failed to calculate installed size: " + e);
|
||||
return Long.MAX_VALUE;
|
||||
@@ -292,60 +238,6 @@ public class DefaultContainerService extends IntentService {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
private String copyPackageToContainerInner(PackageLite pkg, NativeLibraryHelper.Handle handle,
|
||||
String newCid, String key, boolean isExternal, boolean isForwardLocked,
|
||||
String abiOverride) throws IOException {
|
||||
|
||||
// Calculate container size, rounding up to nearest MB and adding an
|
||||
// extra MB for filesystem overhead
|
||||
final long sizeBytes = PackageHelper.calculateInstalledSize(pkg, handle,
|
||||
isForwardLocked, abiOverride);
|
||||
|
||||
// Create new container
|
||||
final String newMountPath = PackageHelper.createSdDir(sizeBytes, newCid, key,
|
||||
Process.myUid(), isExternal);
|
||||
if (newMountPath == null) {
|
||||
throw new IOException("Failed to create container " + newCid);
|
||||
}
|
||||
final File targetDir = new File(newMountPath);
|
||||
|
||||
try {
|
||||
// Copy all APKs
|
||||
copyFile(pkg.baseCodePath, targetDir, "base.apk", isForwardLocked);
|
||||
if (!ArrayUtils.isEmpty(pkg.splitNames)) {
|
||||
for (int i = 0; i < pkg.splitNames.length; i++) {
|
||||
copyFile(pkg.splitCodePaths[i], targetDir,
|
||||
"split_" + pkg.splitNames[i] + ".apk", isForwardLocked);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract native code
|
||||
final File libraryRoot = new File(targetDir, LIB_DIR_NAME);
|
||||
final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
|
||||
abiOverride);
|
||||
if (res != PackageManager.INSTALL_SUCCEEDED) {
|
||||
throw new IOException("Failed to extract native code, res=" + res);
|
||||
}
|
||||
|
||||
if (!PackageHelper.finalizeSdDir(newCid)) {
|
||||
throw new IOException("Failed to finalize " + newCid);
|
||||
}
|
||||
|
||||
if (PackageHelper.isContainerMounted(newCid)) {
|
||||
PackageHelper.unMountSdDir(newCid);
|
||||
}
|
||||
|
||||
} catch (ErrnoException e) {
|
||||
PackageHelper.destroySdDir(newCid);
|
||||
throw e.rethrowAsIOException();
|
||||
} catch (IOException e) {
|
||||
PackageHelper.destroySdDir(newCid);
|
||||
throw e;
|
||||
}
|
||||
|
||||
return newMountPath;
|
||||
}
|
||||
|
||||
private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)
|
||||
throws IOException, RemoteException {
|
||||
copyFile(pkg.baseCodePath, target, "base.apk");
|
||||
@@ -373,28 +265,4 @@ public class DefaultContainerService extends IntentService {
|
||||
IoUtils.closeQuietly(in);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyFile(String sourcePath, File targetDir, String targetName,
|
||||
boolean isForwardLocked) throws IOException, ErrnoException {
|
||||
final File sourceFile = new File(sourcePath);
|
||||
final File targetFile = new File(targetDir, targetName);
|
||||
|
||||
Slog.d(TAG, "Copying " + sourceFile + " to " + targetFile);
|
||||
if (!FileUtils.copyFile(sourceFile, targetFile)) {
|
||||
throw new IOException("Failed to copy " + sourceFile + " to " + targetFile);
|
||||
}
|
||||
|
||||
if (isForwardLocked) {
|
||||
final String publicTargetName = PackageHelper.replaceEnd(targetName,
|
||||
".apk", ".zip");
|
||||
final File publicTargetFile = new File(targetDir, publicTargetName);
|
||||
|
||||
PackageHelper.extractPublicFiles(sourceFile, publicTargetFile);
|
||||
|
||||
Os.chmod(targetFile.getAbsolutePath(), 0640);
|
||||
Os.chmod(publicTargetFile.getAbsolutePath(), 0644);
|
||||
} else {
|
||||
Os.chmod(targetFile.getAbsolutePath(), 0644);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,17 +386,6 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
|
||||
}
|
||||
}
|
||||
|
||||
private static String escapeNull(String arg) {
|
||||
if (TextUtils.isEmpty(arg)) {
|
||||
return "!";
|
||||
} else {
|
||||
if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
|
||||
throw new IllegalArgumentException(arg);
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
/** List of crypto types.
|
||||
* These must match CRYPT_TYPE_XXX in cryptfs.h AND their
|
||||
* corresponding commands in CommandListener.cpp */
|
||||
@@ -416,10 +405,6 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
|
||||
private final Callbacks mCallbacks;
|
||||
private final LockPatternUtils mLockPatternUtils;
|
||||
|
||||
private final Object mUnmountLock = new Object();
|
||||
@GuardedBy("mUnmountLock")
|
||||
private CountDownLatch mUnmountSignal;
|
||||
|
||||
/**
|
||||
* The size of the crypto algorithm key in bits for OBB files. Currently
|
||||
* Twofish is used which takes 128-bit keys.
|
||||
@@ -699,18 +684,6 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void waitForAsecScan() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private void waitForLatch(CountDownLatch latch, String condition) {
|
||||
try {
|
||||
waitForLatch(latch, condition, -1);
|
||||
} catch (TimeoutException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
|
||||
throws TimeoutException {
|
||||
final long startMillis = SystemClock.elapsedRealtime();
|
||||
@@ -1532,48 +1505,6 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
|
||||
mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsbMassStorageConnected() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsbMassStorageEnabled(boolean enable) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsbMassStorageEnabled() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVolumeState(String mountPoint) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExternalStorageEmulated() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int mountVolume(String path) {
|
||||
mount(findVolumeIdForPathOrThrow(path));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unmountVolume(String path, boolean force, boolean removeEncryption) {
|
||||
unmount(findVolumeIdForPathOrThrow(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int formatVolume(String path) {
|
||||
format(findVolumeIdForPathOrThrow(path));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mount(String volId) {
|
||||
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
|
||||
@@ -1594,22 +1525,6 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
|
||||
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
|
||||
|
||||
final VolumeInfo vol = findVolumeByIdOrThrow(volId);
|
||||
|
||||
// TODO: expand PMS to know about multiple volumes
|
||||
if (vol.isPrimaryPhysical()) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mUnmountLock) {
|
||||
mUnmountSignal = new CountDownLatch(1);
|
||||
mPms.updateExternalMediaStatus(false, true);
|
||||
waitForLatch(mUnmountSignal, "mUnmountSignal");
|
||||
mUnmountSignal = null;
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
mVold.unmount(vol.id);
|
||||
} catch (Exception e) {
|
||||
@@ -2004,11 +1919,6 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getStorageUsers(String path) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private void warnOnNotMounted() {
|
||||
synchronized (mLock) {
|
||||
for (int i = 0; i < mVolumes.size(); i++) {
|
||||
@@ -2023,79 +1933,6 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
|
||||
Slog.w(TAG, "No primary storage mounted!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSecureContainerList() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int createSecureContainer(String id, int sizeMb, String fstype, String key,
|
||||
int ownerUid, boolean external) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int resizeSecureContainer(String id, int sizeMb, String key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int finalizeSecureContainer(String id) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fixPermissionsSecureContainer(String id, int gid, String filename) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int destroySecureContainer(String id, boolean force) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int unmountSecureContainer(String id, boolean force) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecureContainerMounted(String id) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int renameSecureContainer(String oldId, String newId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSecureContainerPath(String id) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSecureContainerFilesystemPath(String id) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishMediaUpdate() {
|
||||
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
|
||||
throw new SecurityException("no permission to call finishMediaUpdate()");
|
||||
}
|
||||
if (mUnmountSignal != null) {
|
||||
mUnmountSignal.countDown();
|
||||
} else {
|
||||
Slog.w(TAG, "Odd, nobody asked to unmount?");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
|
||||
if (callerUid == android.os.Process.SYSTEM_UID) {
|
||||
return true;
|
||||
|
||||
@@ -243,35 +243,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public void onSecureContainersAvailable() {
|
||||
synchronized (mSessions) {
|
||||
final ArraySet<String> unclaimed = new ArraySet<>();
|
||||
for (String cid : PackageHelper.getSecureContainerList()) {
|
||||
if (isStageName(cid)) {
|
||||
unclaimed.add(cid);
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore stages claimed by active sessions
|
||||
for (int i = 0; i < mSessions.size(); i++) {
|
||||
final PackageInstallerSession session = mSessions.valueAt(i);
|
||||
final String cid = session.stageCid;
|
||||
|
||||
if (unclaimed.remove(cid)) {
|
||||
// Claimed by active session, mount it
|
||||
PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
|
||||
Process.SYSTEM_UID);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up orphaned staging containers
|
||||
for (String cid : unclaimed) {
|
||||
Slog.w(TAG, "Deleting orphan container " + cid);
|
||||
PackageHelper.destroySdDir(cid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isStageName(String name) {
|
||||
final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
|
||||
final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
|
||||
@@ -671,13 +642,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
return "smdl" + sessionId + ".tmp";
|
||||
}
|
||||
|
||||
static void prepareExternalStageCid(String stageCid, long sizeBytes) throws IOException {
|
||||
if (PackageHelper.createSdDir(sizeBytes, stageCid, PackageManagerService.getEncryptKey(),
|
||||
Process.SYSTEM_UID, true) == null) {
|
||||
throw new IOException("Failed to create session cid: " + stageCid);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionInfo getSessionInfo(int sessionId) {
|
||||
synchronized (mSessions) {
|
||||
|
||||
@@ -36,7 +36,6 @@ import static com.android.internal.util.XmlUtils.writeIntAttribute;
|
||||
import static com.android.internal.util.XmlUtils.writeLongAttribute;
|
||||
import static com.android.internal.util.XmlUtils.writeStringAttribute;
|
||||
import static com.android.internal.util.XmlUtils.writeUriAttribute;
|
||||
import static com.android.server.pm.PackageInstallerService.prepareExternalStageCid;
|
||||
import static com.android.server.pm.PackageInstallerService.prepareStageDir;
|
||||
|
||||
import android.Manifest;
|
||||
@@ -481,12 +480,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
if (stageDir != null) {
|
||||
mResolvedStageDir = stageDir;
|
||||
} else {
|
||||
final String path = PackageHelper.getSdDir(stageCid);
|
||||
if (path != null) {
|
||||
mResolvedStageDir = new File(path);
|
||||
} else {
|
||||
throw new IOException("Failed to resolve path to container " + stageCid);
|
||||
}
|
||||
throw new IOException("Missing stageDir");
|
||||
}
|
||||
}
|
||||
return mResolvedStageDir;
|
||||
@@ -880,14 +874,6 @@ 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) {
|
||||
@@ -924,11 +910,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
// 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.
|
||||
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
|
||||
@@ -953,7 +934,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
|
||||
mRelinquished = true;
|
||||
mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
|
||||
mPm.installStage(mPackageName, stageDir, localObserver, params,
|
||||
mInstallerPackageName, mInstallerUid, user, mCertificates);
|
||||
}
|
||||
|
||||
@@ -1212,11 +1193,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
// straddled between the inherited and staged APKs.
|
||||
final PackageLite pkg = new PackageLite(null, baseApk, null, null, null, null,
|
||||
splitPaths.toArray(new String[splitPaths.size()]), null);
|
||||
final boolean isForwardLocked =
|
||||
(params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
|
||||
|
||||
try {
|
||||
return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, params.abiOverride);
|
||||
return PackageHelper.calculateInstalledSize(pkg, params.abiOverride);
|
||||
} catch (IOException e) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
|
||||
"Failed to calculate install size", e);
|
||||
@@ -1345,52 +1324,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
|
||||
"Failed to fix permissions on container " + cid);
|
||||
}
|
||||
}
|
||||
|
||||
void setPermissionsResult(boolean accepted) {
|
||||
if (!mSealed) {
|
||||
throw new SecurityException("Must be sealed to accept permissions");
|
||||
@@ -1419,20 +1352,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
if (!mPrepared) {
|
||||
if (stageDir != null) {
|
||||
prepareStageDir(stageDir);
|
||||
} else if (stageCid != null) {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
prepareExternalStageCid(stageCid, params.sizeBytes);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
|
||||
// TODO: deliver more granular progress for ASEC allocation
|
||||
mInternalProgress = 0.25f;
|
||||
computeProgressLocked(true);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Exactly one of stageDir or stageCid stage must be set");
|
||||
throw new IllegalArgumentException("stageDir must be set");
|
||||
}
|
||||
|
||||
mPrepared = true;
|
||||
@@ -1534,9 +1455,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
} catch (InstallerException ignored) {
|
||||
}
|
||||
}
|
||||
if (stageCid != null) {
|
||||
PackageHelper.destroySdDir(stageCid);
|
||||
}
|
||||
}
|
||||
|
||||
void dump(IndentingPrintWriter pw) {
|
||||
|
||||
@@ -55,7 +55,6 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_USER_RESTRICTED;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
|
||||
import static android.content.pm.PackageManager.INSTALL_FORWARD_LOCK;
|
||||
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
|
||||
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
||||
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
|
||||
@@ -230,7 +229,6 @@ import android.text.format.DateUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Base64;
|
||||
import android.util.TimingsTraceLog;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.EventLog;
|
||||
import android.util.ExceptionUtils;
|
||||
@@ -244,6 +242,7 @@ import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.TimingsTraceLog;
|
||||
import android.util.Xml;
|
||||
import android.util.jar.StrictJarFile;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
@@ -655,9 +654,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
@GuardedBy("mPackages")
|
||||
private boolean mDexOptDialogShown;
|
||||
|
||||
/** The location for ASEC container files on internal storage. */
|
||||
final String mAsecInternalPath;
|
||||
|
||||
// Used for privilege escalation. MUST NOT BE CALLED WITH mPackages
|
||||
// LOCK HELD. Can be called with mInstallLock held.
|
||||
@GuardedBy("mInstallLock")
|
||||
@@ -1316,7 +1312,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
static final int POST_INSTALL = 9;
|
||||
static final int MCS_RECONNECT = 10;
|
||||
static final int MCS_GIVE_UP = 11;
|
||||
static final int UPDATED_MEDIA_STATUS = 12;
|
||||
static final int WRITE_SETTINGS = 13;
|
||||
static final int WRITE_PACKAGE_RESTRICTIONS = 14;
|
||||
static final int PACKAGE_VERIFIED = 15;
|
||||
@@ -1715,32 +1710,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
|
||||
} break;
|
||||
case UPDATED_MEDIA_STATUS: {
|
||||
if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS");
|
||||
boolean reportStatus = msg.arg1 == 1;
|
||||
boolean doGc = msg.arg2 == 1;
|
||||
if (DEBUG_SD_INSTALL) Log.i(TAG, "reportStatus=" + reportStatus + ", doGc = " + doGc);
|
||||
if (doGc) {
|
||||
// Force a gc to clear up stale containers.
|
||||
Runtime.getRuntime().gc();
|
||||
}
|
||||
if (msg.obj != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<AsecInstallArgs> args = (Set<AsecInstallArgs>) msg.obj;
|
||||
if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers");
|
||||
// Unload containers
|
||||
unloadAllContainers(args);
|
||||
}
|
||||
if (reportStatus) {
|
||||
try {
|
||||
if (DEBUG_SD_INSTALL) Log.i(TAG,
|
||||
"Invoking StorageManagerService call back");
|
||||
PackageHelper.getStorageManager().finishMediaUpdate();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "StorageManagerService not running?");
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case WRITE_SETTINGS: {
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
|
||||
synchronized (mPackages) {
|
||||
@@ -2165,14 +2134,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
unloadPrivatePackages(vol);
|
||||
}
|
||||
}
|
||||
|
||||
if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.isPrimary()) {
|
||||
if (vol.state == VolumeInfo.STATE_MOUNTED) {
|
||||
updateExternalMediaStatus(true, false);
|
||||
} else if (vol.state == VolumeInfo.STATE_EJECTING) {
|
||||
updateExternalMediaStatus(false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2490,7 +2451,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
File dataDir = Environment.getDataDirectory();
|
||||
mAppInstallDir = new File(dataDir, "app");
|
||||
mAppLib32InstallDir = new File(dataDir, "app-lib");
|
||||
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
|
||||
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
|
||||
sUserManager = new UserManagerService(context, this,
|
||||
new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
|
||||
@@ -14876,7 +14836,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
return installReason;
|
||||
}
|
||||
|
||||
void installStage(String packageName, File stagedDir, String stagedCid,
|
||||
void installStage(String packageName, File stagedDir,
|
||||
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
|
||||
String installerPackageName, int installerUid, UserHandle user,
|
||||
Certificate[][] certificates) {
|
||||
@@ -14889,12 +14849,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
sessionParams.originatingUri, sessionParams.referrerUri,
|
||||
sessionParams.originatingUid, installerUid);
|
||||
|
||||
final OriginInfo origin;
|
||||
if (stagedDir != null) {
|
||||
origin = OriginInfo.fromStagedFile(stagedDir);
|
||||
} else {
|
||||
origin = OriginInfo.fromStagedContainer(stagedCid);
|
||||
}
|
||||
final OriginInfo origin = OriginInfo.fromStagedFile(stagedDir);
|
||||
|
||||
final Message msg = mHandler.obtainMessage(INIT_COPY);
|
||||
final int installReason = fixUpInstallReason(installerPackageName, installerUid,
|
||||
@@ -16094,7 +16049,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
* file, or a cluster directory. This location may be untrusted.
|
||||
*/
|
||||
final File file;
|
||||
final String cid;
|
||||
|
||||
/**
|
||||
* Flag indicating that {@link #file} or {@link #cid} has already been
|
||||
@@ -16113,35 +16067,27 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
final File resolvedFile;
|
||||
|
||||
static OriginInfo fromNothing() {
|
||||
return new OriginInfo(null, null, false, false);
|
||||
return new OriginInfo(null, false, false);
|
||||
}
|
||||
|
||||
static OriginInfo fromUntrustedFile(File file) {
|
||||
return new OriginInfo(file, null, false, false);
|
||||
return new OriginInfo(file, false, false);
|
||||
}
|
||||
|
||||
static OriginInfo fromExistingFile(File file) {
|
||||
return new OriginInfo(file, null, false, true);
|
||||
return new OriginInfo(file, false, true);
|
||||
}
|
||||
|
||||
static OriginInfo fromStagedFile(File file) {
|
||||
return new OriginInfo(file, null, true, false);
|
||||
return new OriginInfo(file, true, false);
|
||||
}
|
||||
|
||||
static OriginInfo fromStagedContainer(String cid) {
|
||||
return new OriginInfo(null, cid, true, false);
|
||||
}
|
||||
|
||||
private OriginInfo(File file, String cid, boolean staged, boolean existing) {
|
||||
private OriginInfo(File file, boolean staged, boolean existing) {
|
||||
this.file = file;
|
||||
this.cid = cid;
|
||||
this.staged = staged;
|
||||
this.existing = existing;
|
||||
|
||||
if (cid != null) {
|
||||
resolvedPath = PackageHelper.getSdDir(cid);
|
||||
resolvedFile = new File(resolvedPath);
|
||||
} else if (file != null) {
|
||||
if (file != null) {
|
||||
resolvedPath = file.getAbsolutePath();
|
||||
resolvedFile = file;
|
||||
} else {
|
||||
@@ -16234,7 +16180,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
|
||||
+ " file=" + origin.file + " cid=" + origin.cid + "}";
|
||||
+ " file=" + origin.file + "}";
|
||||
}
|
||||
|
||||
private int installLocationPolicy(PackageInfoLite pkgLite) {
|
||||
@@ -16345,9 +16291,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
if (origin.file != null) {
|
||||
installFlags |= PackageManager.INSTALL_INTERNAL;
|
||||
installFlags &= ~PackageManager.INSTALL_EXTERNAL;
|
||||
} else if (origin.cid != null) {
|
||||
installFlags |= PackageManager.INSTALL_EXTERNAL;
|
||||
installFlags &= ~PackageManager.INSTALL_INTERNAL;
|
||||
} else {
|
||||
throw new IllegalStateException("Invalid stage location");
|
||||
}
|
||||
@@ -16385,7 +16328,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
Environment.getDataDirectory());
|
||||
|
||||
final long sizeBytes = mContainerService.calculateInstalledSize(
|
||||
origin.resolvedPath, isForwardLocked(), packageAbiOverride);
|
||||
origin.resolvedPath, packageAbiOverride);
|
||||
|
||||
try {
|
||||
mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
|
||||
@@ -16622,43 +16565,11 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
mArgs = createInstallArgs(this);
|
||||
mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
public boolean isForwardLocked() {
|
||||
return (installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used during creation of InstallArgs
|
||||
*
|
||||
* @param installFlags package installation flags
|
||||
* @return true if should be installed on external storage
|
||||
*/
|
||||
private static boolean installOnExternalAsec(int installFlags) {
|
||||
if ((installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
|
||||
return false;
|
||||
}
|
||||
if ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used during creation of InstallArgs
|
||||
*
|
||||
* @param installFlags package installation flags
|
||||
* @return true if should be installed as forward locked
|
||||
*/
|
||||
private static boolean installForwardLocked(int installFlags) {
|
||||
return (installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
|
||||
}
|
||||
|
||||
private InstallArgs createInstallArgs(InstallParams params) {
|
||||
if (params.move != null) {
|
||||
return new MoveInstallArgs(params);
|
||||
} else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
|
||||
return new AsecInstallArgs(params);
|
||||
} else {
|
||||
return new FileInstallArgs(params);
|
||||
}
|
||||
@@ -16670,27 +16581,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
*/
|
||||
private InstallArgs createInstallArgsForExisting(int installFlags, String codePath,
|
||||
String resourcePath, String[] instructionSets) {
|
||||
final boolean isInAsec;
|
||||
if (installOnExternalAsec(installFlags)) {
|
||||
/* Apps on SD card are always in ASEC containers. */
|
||||
isInAsec = true;
|
||||
} else if (installForwardLocked(installFlags)
|
||||
&& !codePath.startsWith(mDrmAppPrivateInstallDir.getAbsolutePath())) {
|
||||
/*
|
||||
* Forward-locked apps are only in ASEC containers if they're the
|
||||
* new style
|
||||
*/
|
||||
isInAsec = true;
|
||||
} else {
|
||||
isInAsec = false;
|
||||
}
|
||||
|
||||
if (isInAsec) {
|
||||
return new AsecInstallArgs(codePath, instructionSets,
|
||||
installOnExternalAsec(installFlags), installForwardLocked(installFlags));
|
||||
} else {
|
||||
return new FileInstallArgs(codePath, resourcePath, instructionSets);
|
||||
}
|
||||
return new FileInstallArgs(codePath, resourcePath, instructionSets);
|
||||
}
|
||||
|
||||
static abstract class InstallArgs {
|
||||
@@ -17024,11 +16915,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAsecExternal(String cid) {
|
||||
final String asecPath = PackageHelper.getSdFilesystem(cid);
|
||||
return !asecPath.startsWith(mAsecInternalPath);
|
||||
}
|
||||
|
||||
private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
|
||||
PackageManagerException {
|
||||
if (copyRet < 0) {
|
||||
@@ -17050,308 +16936,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
return subStr1.substring(sidx+1, eidx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logic to handle installation of ASEC applications, including copying and
|
||||
* renaming logic.
|
||||
*/
|
||||
class AsecInstallArgs extends InstallArgs {
|
||||
static final String RES_FILE_NAME = "pkg.apk";
|
||||
static final String PUBLIC_RES_FILE_NAME = "res.zip";
|
||||
|
||||
String cid;
|
||||
String packagePath;
|
||||
String resourcePath;
|
||||
|
||||
/** New install */
|
||||
AsecInstallArgs(InstallParams params) {
|
||||
super(params.origin, params.move, params.observer, params.installFlags,
|
||||
params.installerPackageName, params.volumeUuid,
|
||||
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
|
||||
params.grantedRuntimePermissions,
|
||||
params.traceMethod, params.traceCookie, params.certificates,
|
||||
params.installReason);
|
||||
}
|
||||
|
||||
/** Existing install */
|
||||
AsecInstallArgs(String fullCodePath, String[] instructionSets,
|
||||
boolean isExternal, boolean isForwardLocked) {
|
||||
super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
|
||||
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
|
||||
instructionSets, null, null, null, 0, null /*certificates*/,
|
||||
PackageManager.INSTALL_REASON_UNKNOWN);
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Extract cid from fullCodePath
|
||||
int eidx = fullCodePath.lastIndexOf("/");
|
||||
String subStr1 = fullCodePath.substring(0, eidx);
|
||||
int sidx = subStr1.lastIndexOf("/");
|
||||
cid = subStr1.substring(sidx+1, eidx);
|
||||
setMountPath(subStr1);
|
||||
}
|
||||
|
||||
AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
|
||||
super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
|
||||
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
|
||||
instructionSets, null, null, null, 0, null /*certificates*/,
|
||||
PackageManager.INSTALL_REASON_UNKNOWN);
|
||||
this.cid = cid;
|
||||
setMountPath(PackageHelper.getSdDir(cid));
|
||||
}
|
||||
|
||||
void createCopyFile() {
|
||||
cid = mInstallerService.allocateExternalStageCidLegacy();
|
||||
}
|
||||
|
||||
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
|
||||
if (origin.staged && origin.cid != null) {
|
||||
if (DEBUG_INSTALL) Slog.d(TAG, origin.cid + " already staged; skipping copy");
|
||||
cid = origin.cid;
|
||||
setMountPath(PackageHelper.getSdDir(cid));
|
||||
return PackageManager.INSTALL_SUCCEEDED;
|
||||
}
|
||||
|
||||
if (temp) {
|
||||
createCopyFile();
|
||||
} else {
|
||||
/*
|
||||
* Pre-emptively destroy the container since it's destroyed if
|
||||
* copying fails due to it existing anyway.
|
||||
*/
|
||||
PackageHelper.destroySdDir(cid);
|
||||
}
|
||||
|
||||
final String newMountPath = imcs.copyPackageToContainer(
|
||||
origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternalAsec(),
|
||||
isFwdLocked(), deriveAbiOverride(abiOverride, null /* settings */));
|
||||
|
||||
if (newMountPath != null) {
|
||||
setMountPath(newMountPath);
|
||||
return PackageManager.INSTALL_SUCCEEDED;
|
||||
} else {
|
||||
return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String getCodePath() {
|
||||
return packagePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getResourcePath() {
|
||||
return resourcePath;
|
||||
}
|
||||
|
||||
int doPreInstall(int status) {
|
||||
if (status != PackageManager.INSTALL_SUCCEEDED) {
|
||||
// Destroy container
|
||||
PackageHelper.destroySdDir(cid);
|
||||
} else {
|
||||
boolean mounted = PackageHelper.isContainerMounted(cid);
|
||||
if (!mounted) {
|
||||
String newMountPath = PackageHelper.mountSdDir(cid, getEncryptKey(),
|
||||
Process.SYSTEM_UID);
|
||||
if (newMountPath != null) {
|
||||
setMountPath(newMountPath);
|
||||
} else {
|
||||
return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
|
||||
String newCacheId = getNextCodePath(oldCodePath, pkg.packageName, "/" + RES_FILE_NAME);
|
||||
String newMountPath = null;
|
||||
if (PackageHelper.isContainerMounted(cid)) {
|
||||
// Unmount the container
|
||||
if (!PackageHelper.unMountSdDir(cid)) {
|
||||
Slog.i(TAG, "Failed to unmount " + cid + " before renaming");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!PackageHelper.renameSdDir(cid, newCacheId)) {
|
||||
Slog.e(TAG, "Failed to rename " + cid + " to " + newCacheId +
|
||||
" which might be stale. Will try to clean up.");
|
||||
// Clean up the stale container and proceed to recreate.
|
||||
if (!PackageHelper.destroySdDir(newCacheId)) {
|
||||
Slog.e(TAG, "Very strange. Cannot clean up stale container " + newCacheId);
|
||||
return false;
|
||||
}
|
||||
// Successfully cleaned up stale container. Try to rename again.
|
||||
if (!PackageHelper.renameSdDir(cid, newCacheId)) {
|
||||
Slog.e(TAG, "Failed to rename " + cid + " to " + newCacheId
|
||||
+ " inspite of cleaning it up.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!PackageHelper.isContainerMounted(newCacheId)) {
|
||||
Slog.w(TAG, "Mounting container " + newCacheId);
|
||||
newMountPath = PackageHelper.mountSdDir(newCacheId,
|
||||
getEncryptKey(), Process.SYSTEM_UID);
|
||||
} else {
|
||||
newMountPath = PackageHelper.getSdDir(newCacheId);
|
||||
}
|
||||
if (newMountPath == null) {
|
||||
Slog.w(TAG, "Failed to get cache path for " + newCacheId);
|
||||
return false;
|
||||
}
|
||||
Log.i(TAG, "Succesfully renamed " + cid +
|
||||
" to " + newCacheId +
|
||||
" at new path: " + newMountPath);
|
||||
cid = newCacheId;
|
||||
|
||||
final File beforeCodeFile = new File(packagePath);
|
||||
setMountPath(newMountPath);
|
||||
final File afterCodeFile = new File(packagePath);
|
||||
|
||||
// Reflect the rename in scanned details
|
||||
pkg.setCodePath(afterCodeFile.getAbsolutePath());
|
||||
pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
|
||||
afterCodeFile, pkg.baseCodePath));
|
||||
pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
|
||||
afterCodeFile, pkg.splitCodePaths));
|
||||
|
||||
// Reflect the rename in app info
|
||||
pkg.setApplicationVolumeUuid(pkg.volumeUuid);
|
||||
pkg.setApplicationInfoCodePath(pkg.codePath);
|
||||
pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
|
||||
pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
|
||||
pkg.setApplicationInfoResourcePath(pkg.codePath);
|
||||
pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
|
||||
pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setMountPath(String mountPath) {
|
||||
final File mountFile = new File(mountPath);
|
||||
|
||||
final File monolithicFile = new File(mountFile, RES_FILE_NAME);
|
||||
if (monolithicFile.exists()) {
|
||||
packagePath = monolithicFile.getAbsolutePath();
|
||||
if (isFwdLocked()) {
|
||||
resourcePath = new File(mountFile, PUBLIC_RES_FILE_NAME).getAbsolutePath();
|
||||
} else {
|
||||
resourcePath = packagePath;
|
||||
}
|
||||
} else {
|
||||
packagePath = mountFile.getAbsolutePath();
|
||||
resourcePath = packagePath;
|
||||
}
|
||||
}
|
||||
|
||||
int doPostInstall(int status, int uid) {
|
||||
if (status != PackageManager.INSTALL_SUCCEEDED) {
|
||||
cleanUp();
|
||||
} else {
|
||||
final int groupOwner;
|
||||
final String protectedFile;
|
||||
if (isFwdLocked()) {
|
||||
groupOwner = UserHandle.getSharedAppGid(uid);
|
||||
protectedFile = RES_FILE_NAME;
|
||||
} else {
|
||||
groupOwner = -1;
|
||||
protectedFile = null;
|
||||
}
|
||||
|
||||
if (uid < Process.FIRST_APPLICATION_UID
|
||||
|| !PackageHelper.fixSdPermissions(cid, groupOwner, protectedFile)) {
|
||||
Slog.e(TAG, "Failed to finalize " + cid);
|
||||
PackageHelper.destroySdDir(cid);
|
||||
return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
|
||||
}
|
||||
|
||||
boolean mounted = PackageHelper.isContainerMounted(cid);
|
||||
if (!mounted) {
|
||||
PackageHelper.mountSdDir(cid, getEncryptKey(), Process.myUid());
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
private void cleanUp() {
|
||||
if (DEBUG_SD_INSTALL) Slog.i(TAG, "cleanUp");
|
||||
|
||||
// Destroy secure container
|
||||
PackageHelper.destroySdDir(cid);
|
||||
}
|
||||
|
||||
private List<String> getAllCodePaths() {
|
||||
final File codeFile = new File(getCodePath());
|
||||
if (codeFile != null && codeFile.exists()) {
|
||||
try {
|
||||
final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0);
|
||||
return pkg.getAllCodePaths();
|
||||
} catch (PackageParserException e) {
|
||||
// Ignored; we tried our best
|
||||
}
|
||||
}
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
void cleanUpResourcesLI() {
|
||||
// Enumerate all code paths before deleting
|
||||
cleanUpResourcesLI(getAllCodePaths());
|
||||
}
|
||||
|
||||
private void cleanUpResourcesLI(List<String> allCodePaths) {
|
||||
cleanUp();
|
||||
removeDexFiles(allCodePaths, instructionSets);
|
||||
}
|
||||
|
||||
String getPackageName() {
|
||||
return getAsecPackageName(cid);
|
||||
}
|
||||
|
||||
boolean doPostDeleteLI(boolean delete) {
|
||||
if (DEBUG_SD_INSTALL) Slog.i(TAG, "doPostDeleteLI() del=" + delete);
|
||||
final List<String> allCodePaths = getAllCodePaths();
|
||||
boolean mounted = PackageHelper.isContainerMounted(cid);
|
||||
if (mounted) {
|
||||
// Unmount first
|
||||
if (PackageHelper.unMountSdDir(cid)) {
|
||||
mounted = false;
|
||||
}
|
||||
}
|
||||
if (!mounted && delete) {
|
||||
cleanUpResourcesLI(allCodePaths);
|
||||
}
|
||||
return !mounted;
|
||||
}
|
||||
|
||||
@Override
|
||||
int doPreCopy() {
|
||||
if (isFwdLocked()) {
|
||||
if (!PackageHelper.fixSdPermissions(cid, getPackageUid(DEFAULT_CONTAINER_PACKAGE,
|
||||
MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM), RES_FILE_NAME)) {
|
||||
return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return PackageManager.INSTALL_SUCCEEDED;
|
||||
}
|
||||
|
||||
@Override
|
||||
int doPostCopy(int uid) {
|
||||
if (isFwdLocked()) {
|
||||
if (uid < Process.FIRST_APPLICATION_UID
|
||||
|| !PackageHelper.fixSdPermissions(cid, UserHandle.getSharedAppGid(uid),
|
||||
RES_FILE_NAME)) {
|
||||
Slog.e(TAG, "Failed to finalize " + cid);
|
||||
PackageHelper.destroySdDir(cid);
|
||||
return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return PackageManager.INSTALL_SUCCEEDED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logic to handle movement of existing installed applications.
|
||||
*/
|
||||
@@ -23430,135 +23014,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update media status on PackageManager.
|
||||
*/
|
||||
@Override
|
||||
public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
|
||||
enforceSystemOrRoot("Media status can only be updated by the system");
|
||||
// reader; this apparently protects mMediaMounted, but should probably
|
||||
// be a different lock in that case.
|
||||
synchronized (mPackages) {
|
||||
Log.i(TAG, "Updating external media status from "
|
||||
+ (mMediaMounted ? "mounted" : "unmounted") + " to "
|
||||
+ (mediaStatus ? "mounted" : "unmounted"));
|
||||
if (DEBUG_SD_INSTALL)
|
||||
Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" + mediaStatus
|
||||
+ ", mMediaMounted=" + mMediaMounted);
|
||||
if (mediaStatus == mMediaMounted) {
|
||||
final Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1
|
||||
: 0, -1);
|
||||
mHandler.sendMessage(msg);
|
||||
return;
|
||||
}
|
||||
mMediaMounted = mediaStatus;
|
||||
}
|
||||
// Queue up an async operation since the package installation may take a
|
||||
// little while.
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
updateExternalMediaStatusInner(mediaStatus, reportStatus, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by StorageManagerService when the initial ASECs to scan are available.
|
||||
* Should block until all the ASEC containers are finished being scanned.
|
||||
*/
|
||||
public void scanAvailableAsecs() {
|
||||
updateExternalMediaStatusInner(true, false, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect information of applications on external media, map them against
|
||||
* existing containers and update information based on current mount status.
|
||||
* Please note that we always have to report status if reportStatus has been
|
||||
* set to true especially when unloading packages.
|
||||
*/
|
||||
private void updateExternalMediaStatusInner(boolean isMounted, boolean reportStatus,
|
||||
boolean externalStorage) {
|
||||
ArrayMap<AsecInstallArgs, String> processCids = new ArrayMap<>();
|
||||
int[] uidArr = EmptyArray.INT;
|
||||
|
||||
final String[] list = PackageHelper.getSecureContainerList();
|
||||
if (ArrayUtils.isEmpty(list)) {
|
||||
Log.i(TAG, "No secure containers found");
|
||||
} else {
|
||||
// Process list of secure containers and categorize them
|
||||
// as active or stale based on their package internal state.
|
||||
|
||||
// reader
|
||||
synchronized (mPackages) {
|
||||
for (String cid : list) {
|
||||
// Leave stages untouched for now; installer service owns them
|
||||
if (PackageInstallerService.isStageName(cid)) continue;
|
||||
|
||||
if (DEBUG_SD_INSTALL)
|
||||
Log.i(TAG, "Processing container " + cid);
|
||||
String pkgName = getAsecPackageName(cid);
|
||||
if (pkgName == null) {
|
||||
Slog.i(TAG, "Found stale container " + cid + " with no package name");
|
||||
continue;
|
||||
}
|
||||
if (DEBUG_SD_INSTALL)
|
||||
Log.i(TAG, "Looking for pkg : " + pkgName);
|
||||
|
||||
final PackageSetting ps = mSettings.mPackages.get(pkgName);
|
||||
if (ps == null) {
|
||||
Slog.i(TAG, "Found stale container " + cid + " with no matching settings");
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip packages that are not external if we're unmounting
|
||||
* external storage.
|
||||
*/
|
||||
if (externalStorage && !isMounted && !isExternal(ps)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final AsecInstallArgs args = new AsecInstallArgs(cid,
|
||||
getAppDexInstructionSets(ps), ps.isForwardLocked());
|
||||
// The package status is changed only if the code path
|
||||
// matches between settings and the container id.
|
||||
if (ps.codePathString != null
|
||||
&& ps.codePathString.startsWith(args.getCodePath())) {
|
||||
if (DEBUG_SD_INSTALL) {
|
||||
Log.i(TAG, "Container : " + cid + " corresponds to pkg : " + pkgName
|
||||
+ " at code path: " + ps.codePathString);
|
||||
}
|
||||
|
||||
// We do have a valid package installed on sdcard
|
||||
processCids.put(args, ps.codePathString);
|
||||
final int uid = ps.appId;
|
||||
if (uid != -1) {
|
||||
uidArr = ArrayUtils.appendInt(uidArr, uid);
|
||||
}
|
||||
} else {
|
||||
Slog.i(TAG, "Found stale container " + cid + ": expected codePath="
|
||||
+ ps.codePathString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Arrays.sort(uidArr);
|
||||
}
|
||||
|
||||
// Process packages with valid entries.
|
||||
if (isMounted) {
|
||||
if (DEBUG_SD_INSTALL)
|
||||
Log.i(TAG, "Loading packages");
|
||||
loadMediaPackages(processCids, uidArr, externalStorage);
|
||||
startCleaningPackages();
|
||||
mInstallerService.onSecureContainersAvailable();
|
||||
} else {
|
||||
if (DEBUG_SD_INSTALL)
|
||||
Log.i(TAG, "Unloading packages");
|
||||
unloadMediaPackages(processCids, uidArr, reportStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
|
||||
ArrayList<ApplicationInfo> infos, IIntentReceiver finishedReceiver) {
|
||||
final int size = infos.size();
|
||||
@@ -23598,193 +23053,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look at potentially valid container ids from processCids If package
|
||||
* information doesn't match the one on record or package scanning fails,
|
||||
* the cid is added to list of removeCids. We currently don't delete stale
|
||||
* containers.
|
||||
*/
|
||||
private void loadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int[] uidArr,
|
||||
boolean externalStorage) {
|
||||
ArrayList<String> pkgList = new ArrayList<String>();
|
||||
Set<AsecInstallArgs> keys = processCids.keySet();
|
||||
|
||||
for (AsecInstallArgs args : keys) {
|
||||
String codePath = processCids.get(args);
|
||||
if (DEBUG_SD_INSTALL)
|
||||
Log.i(TAG, "Loading container : " + args.cid);
|
||||
int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
|
||||
try {
|
||||
// Make sure there are no container errors first.
|
||||
if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) {
|
||||
Slog.e(TAG, "Failed to mount cid : " + args.cid
|
||||
+ " when installing from sdcard");
|
||||
continue;
|
||||
}
|
||||
// Check code path here.
|
||||
if (codePath == null || !codePath.startsWith(args.getCodePath())) {
|
||||
Slog.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath()
|
||||
+ " does not match one in settings " + codePath);
|
||||
continue;
|
||||
}
|
||||
// Parse package
|
||||
int parseFlags = mDefParseFlags;
|
||||
if (args.isExternalAsec()) {
|
||||
parseFlags |= PackageParser.PARSE_EXTERNAL_STORAGE;
|
||||
}
|
||||
if (args.isFwdLocked()) {
|
||||
parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
|
||||
}
|
||||
|
||||
synchronized (mInstallLock) {
|
||||
PackageParser.Package pkg = null;
|
||||
try {
|
||||
// Sadly we don't know the package name yet to freeze it
|
||||
pkg = scanPackageTracedLI(new File(codePath), parseFlags,
|
||||
SCAN_IGNORE_FROZEN, 0, null);
|
||||
} catch (PackageManagerException e) {
|
||||
Slog.w(TAG, "Failed to scan " + codePath + ": " + e.getMessage());
|
||||
}
|
||||
// Scan the package
|
||||
if (pkg != null) {
|
||||
/*
|
||||
* TODO why is the lock being held? doPostInstall is
|
||||
* called in other places without the lock. This needs
|
||||
* to be straightened out.
|
||||
*/
|
||||
// writer
|
||||
synchronized (mPackages) {
|
||||
retCode = PackageManager.INSTALL_SUCCEEDED;
|
||||
pkgList.add(pkg.packageName);
|
||||
// Post process args
|
||||
args.doPostInstall(PackageManager.INSTALL_SUCCEEDED,
|
||||
pkg.applicationInfo.uid);
|
||||
}
|
||||
} else {
|
||||
Slog.i(TAG, "Failed to install pkg from " + codePath + " from sdcard");
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (retCode != PackageManager.INSTALL_SUCCEEDED) {
|
||||
Log.w(TAG, "Container " + args.cid + " is stale, retCode=" + retCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
// writer
|
||||
synchronized (mPackages) {
|
||||
// If the platform SDK has changed since the last time we booted,
|
||||
// we need to re-grant app permission to catch any new ones that
|
||||
// appear. This is really a hack, and means that apps can in some
|
||||
// cases get permissions that the user didn't initially explicitly
|
||||
// allow... it would be nice to have some better way to handle
|
||||
// this situation.
|
||||
final VersionInfo ver = externalStorage ? mSettings.getExternalVersion()
|
||||
: mSettings.getInternalVersion();
|
||||
final String volumeUuid = externalStorage ? StorageManager.UUID_PRIMARY_PHYSICAL
|
||||
: StorageManager.UUID_PRIVATE_INTERNAL;
|
||||
|
||||
int updateFlags = UPDATE_PERMISSIONS_ALL;
|
||||
if (ver.sdkVersion != mSdkVersion) {
|
||||
logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to "
|
||||
+ mSdkVersion + "; regranting permissions for external");
|
||||
updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
|
||||
}
|
||||
updatePermissionsLPw(null, null, volumeUuid, updateFlags);
|
||||
|
||||
// Yay, everything is now upgraded
|
||||
ver.forceCurrent();
|
||||
|
||||
// can downgrade to reader
|
||||
// Persist settings
|
||||
mSettings.writeLPr();
|
||||
}
|
||||
// Send a broadcast to let everyone know we are done processing
|
||||
if (pkgList.size() > 0) {
|
||||
sendResourcesChangedBroadcast(true, false, pkgList, uidArr, null);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility method to unload a list of specified containers
|
||||
*/
|
||||
private void unloadAllContainers(Set<AsecInstallArgs> cidArgs) {
|
||||
// Just unmount all valid containers.
|
||||
for (AsecInstallArgs arg : cidArgs) {
|
||||
synchronized (mInstallLock) {
|
||||
arg.doPostDeleteLI(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unload packages mounted on external media. This involves deleting package
|
||||
* data from internal structures, sending broadcasts about disabled packages,
|
||||
* gc'ing to free up references, unmounting all secure containers
|
||||
* corresponding to packages on external media, and posting a
|
||||
* UPDATED_MEDIA_STATUS message if status has been requested. Please note
|
||||
* that we always have to post this message if status has been requested no
|
||||
* matter what.
|
||||
*/
|
||||
private void unloadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int uidArr[],
|
||||
final boolean reportStatus) {
|
||||
if (DEBUG_SD_INSTALL)
|
||||
Log.i(TAG, "unloading media packages");
|
||||
ArrayList<String> pkgList = new ArrayList<String>();
|
||||
ArrayList<AsecInstallArgs> failedList = new ArrayList<AsecInstallArgs>();
|
||||
final Set<AsecInstallArgs> keys = processCids.keySet();
|
||||
for (AsecInstallArgs args : keys) {
|
||||
String pkgName = args.getPackageName();
|
||||
if (DEBUG_SD_INSTALL)
|
||||
Log.i(TAG, "Trying to unload pkg : " + pkgName);
|
||||
// Delete package internally
|
||||
PackageRemovedInfo outInfo = new PackageRemovedInfo(this);
|
||||
synchronized (mInstallLock) {
|
||||
final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
|
||||
final boolean res;
|
||||
try (PackageFreezer freezer = freezePackageForDelete(pkgName, deleteFlags,
|
||||
"unloadMediaPackages")) {
|
||||
res = deletePackageLIF(pkgName, null, false, null, deleteFlags, outInfo, false,
|
||||
null);
|
||||
}
|
||||
if (res) {
|
||||
pkgList.add(pkgName);
|
||||
} else {
|
||||
Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
|
||||
failedList.add(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reader
|
||||
synchronized (mPackages) {
|
||||
// We didn't update the settings after removing each package;
|
||||
// write them now for all packages.
|
||||
mSettings.writeLPr();
|
||||
}
|
||||
|
||||
// We have to absolutely send UPDATED_MEDIA_STATUS only
|
||||
// after confirming that all the receivers processed the ordered
|
||||
// broadcast when packages get disabled, force a gc to clean things up.
|
||||
// and unload all the containers.
|
||||
if (pkgList.size() > 0) {
|
||||
sendResourcesChangedBroadcast(false, false, pkgList, uidArr,
|
||||
new IIntentReceiver.Stub() {
|
||||
public void performReceive(Intent intent, int resultCode, String data,
|
||||
Bundle extras, boolean ordered, boolean sticky,
|
||||
int sendingUser) throws RemoteException {
|
||||
Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
|
||||
reportStatus ? 1 : 0, 1, keys);
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1 : 0, -1,
|
||||
keys);
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadPrivatePackages(final VolumeInfo vol) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
|
||||
@@ -183,7 +183,7 @@ class PackageManagerShellCommand extends ShellCommand {
|
||||
PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
|
||||
null, null);
|
||||
params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
|
||||
pkgLite, false, params.sessionParams.abiOverride));
|
||||
pkgLite, params.sessionParams.abiOverride));
|
||||
} catch (PackageParserException | IOException e) {
|
||||
pw.println("Error: Failed to parse APK file: " + file);
|
||||
throw new IllegalArgumentException(
|
||||
|
||||
Reference in New Issue
Block a user