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:
Jeff Sharkey
2017-09-21 19:09:30 -06:00
parent 1ec536fa4a
commit f8bb2445ff
14 changed files with 39 additions and 2856 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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