diff options
17 files changed, 622 insertions, 248 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 51152af..23a8629 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -30,6 +30,7 @@ import android.content.pm.FeatureInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageInstaller; import android.content.pm.IPackageManager; +import android.content.pm.IPackageMoveObserver; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; @@ -55,12 +56,12 @@ import android.os.UserManager; import android.text.TextUtils; import android.util.Log; +import libcore.io.IoUtils; + import com.android.internal.content.PackageHelper; import com.android.internal.util.ArrayUtils; import com.android.internal.util.SizedInputStream; -import libcore.io.IoUtils; - import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -234,6 +235,10 @@ public final class Pm { return runForceDexOpt(); } + if ("move".equals(op)) { + return runMove(); + } + try { if (args.length == 1) { if (args[0].equalsIgnoreCase("-l")) { @@ -1278,6 +1283,51 @@ public final class Pm { } } + class LocalPackageMoveObserver extends IPackageMoveObserver.Stub { + boolean finished; + int returnCode; + + @Override + public void packageMoved(String packageName, int returnCode) throws RemoteException { + synchronized (this) { + this.finished = true; + this.returnCode = returnCode; + notifyAll(); + } + } + } + + public int runMove() { + final String packageName = nextArg(); + String volumeUuid = nextArg(); + if ("internal".equals(volumeUuid)) { + volumeUuid = null; + } + + final LocalPackageMoveObserver obs = new LocalPackageMoveObserver(); + try { + mPm.movePackageAndData(packageName, volumeUuid, obs); + + synchronized (obs) { + while (!obs.finished) { + try { + obs.wait(); + } catch (InterruptedException e) { + } + } + if (obs.returnCode == PackageManager.MOVE_SUCCEEDED) { + System.out.println("Success"); + return 0; + } else { + System.err.println("Failure [" + obs.returnCode + "]"); + return 1; + } + } + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + private int runUninstall() throws RemoteException { int flags = 0; int userId = UserHandle.USER_ALL; @@ -1820,6 +1870,7 @@ public final class Pm { System.err.println(" pm install-abandon SESSION_ID"); System.err.println(" pm uninstall [-k] [--user USER_ID] PACKAGE"); System.err.println(" pm set-installer PACKAGE INSTALLER"); + System.err.println(" pm move PACKAGE [internal|UUID]"); System.err.println(" pm clear [--user USER_ID] PACKAGE"); System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT"); System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT"); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 6ec5457..10dcd85 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -62,19 +62,19 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Process; import android.os.RemoteException; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.util.ArrayMap; import android.util.Log; import android.view.Display; -import android.os.SystemProperties; + +import dalvik.system.VMRuntime; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.internal.util.UserIcons; -import dalvik.system.VMRuntime; - import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -1363,7 +1363,17 @@ final class ApplicationPackageManager extends PackageManager { try { mPM.movePackage(packageName, observer, flags); } catch (RemoteException e) { - // Should never happen! + throw e.rethrowAsRuntimeException(); + } + } + + @Override + public void movePackageAndData(String packageName, String volumeUuid, + IPackageMoveObserver observer) { + try { + mPM.movePackageAndData(packageName, volumeUuid, observer); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); } } diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 8567c01..5bdb7bb 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -459,6 +459,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public int largestWidthLimitDp = 0; /** {@hide} */ + public String volumeUuid; + /** {@hide} */ public String scanSourceDir; /** {@hide} */ public String scanPublicSourceDir; @@ -726,6 +728,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { requiresSmallestWidthDp = orig.requiresSmallestWidthDp; compatibleWidthLimitDp = orig.compatibleWidthLimitDp; largestWidthLimitDp = orig.largestWidthLimitDp; + volumeUuid = orig.volumeUuid; scanSourceDir = orig.scanSourceDir; scanPublicSourceDir = orig.scanPublicSourceDir; sourceDir = orig.sourceDir; @@ -778,6 +781,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(requiresSmallestWidthDp); dest.writeInt(compatibleWidthLimitDp); dest.writeInt(largestWidthLimitDp); + dest.writeString(volumeUuid); dest.writeString(scanSourceDir); dest.writeString(scanPublicSourceDir); dest.writeString(sourceDir); @@ -829,6 +833,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { requiresSmallestWidthDp = source.readInt(); compatibleWidthLimitDp = source.readInt(); largestWidthLimitDp = source.readInt(); + volumeUuid = source.readString(); scanSourceDir = source.readString(); scanPublicSourceDir = source.readString(); sourceDir = source.readString(); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 649bb47..eed0df5 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -432,7 +432,8 @@ interface IPackageManager { PackageCleanItem nextPackageToClean(in PackageCleanItem lastPackage); void movePackage(String packageName, IPackageMoveObserver observer, int flags); - + void movePackageAndData(String packageName, String volumeUuid, IPackageMoveObserver observer); + boolean addPermissionAsync(in PermissionInfo info); boolean setInstallLocation(int loc); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 80efd0b..15a7bf9 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -887,6 +887,8 @@ public class PackageInstaller { public Uri referrerUri; /** {@hide} */ public String abiOverride; + /** {@hide} */ + public String volumeUuid; /** * Construct parameters for a new package install session. @@ -911,6 +913,7 @@ public class PackageInstaller { originatingUri = source.readParcelable(null); referrerUri = source.readParcelable(null); abiOverride = source.readString(); + volumeUuid = source.readString(); } /** @@ -1008,6 +1011,7 @@ public class PackageInstaller { pw.printPair("originatingUri", originatingUri); pw.printPair("referrerUri", referrerUri); pw.printPair("abiOverride", abiOverride); + pw.printPair("volumeUuid", volumeUuid); pw.println(); } @@ -1028,6 +1032,7 @@ public class PackageInstaller { dest.writeParcelable(originatingUri, flags); dest.writeParcelable(referrerUri, flags); dest.writeString(abiOverride); + dest.writeString(volumeUuid); } public static final Parcelable.Creator<SessionParams> diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 46d6ffb3..4c99d09 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -43,7 +43,9 @@ import android.os.Bundle; import android.os.Environment; import android.os.RemoteException; import android.os.UserHandle; +import android.os.storage.VolumeInfo; import android.util.AndroidException; + import com.android.internal.util.ArrayUtils; import java.io.File; @@ -339,15 +341,17 @@ public abstract class PackageManager { public static final int INSTALL_ALLOW_TEST = 0x00000004; /** - * Flag parameter for {@link #installPackage} to indicate that this - * package has to be installed on the sdcard. + * Flag parameter for {@link #installPackage} to indicate that this package + * must be installed to an ASEC on a {@link VolumeInfo#TYPE_PUBLIC}. + * * @hide */ public static final int INSTALL_EXTERNAL = 0x00000008; /** * Flag parameter for {@link #installPackage} to indicate that this package - * has to be installed on the sdcard. + * must be installed to internal storage. + * * @hide */ public static final int INSTALL_INTERNAL = 0x00000010; @@ -4099,8 +4103,12 @@ public abstract class PackageManager { * * @hide */ - public abstract void movePackage( - String packageName, IPackageMoveObserver observer, int flags); + @Deprecated + public abstract void movePackage(String packageName, IPackageMoveObserver observer, int flags); + + /** {@hide} */ + public abstract void movePackageAndData(String packageName, String volumeUuid, + IPackageMoveObserver observer); /** * Returns the device identity that verifiers can use to associate their scheme to a particular diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index f4ad434..c1e6a4d 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -604,7 +604,7 @@ public class PackageParser { public final static int PARSE_MUST_BE_APK = 1<<2; public final static int PARSE_IGNORE_PROCESSES = 1<<3; public final static int PARSE_FORWARD_LOCK = 1<<4; - public final static int PARSE_ON_SDCARD = 1<<5; + public final static int PARSE_EXTERNAL_STORAGE = 1<<5; public final static int PARSE_IS_SYSTEM_DIR = 1<<6; public final static int PARSE_IS_PRIVILEGED = 1<<7; public final static int PARSE_COLLECT_CERTIFICATES = 1<<8; @@ -1408,7 +1408,7 @@ public class PackageParser { } /* Set the global "on SD card" flag */ - if ((flags & PARSE_ON_SDCARD) != 0) { + if ((flags & PARSE_EXTERNAL_STORAGE) != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 486f9b4..5a5d8b7 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -43,6 +43,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; /** @@ -231,8 +232,7 @@ public class StorageManager { mLooper = looper; mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); if (mMountService == null) { - Log.e(TAG, "Unable to connect to mount service! - is it running yet?"); - return; + throw new IllegalStateException("Failed to find running mount service"); } } @@ -442,6 +442,42 @@ public class StorageManager { } /** {@hide} */ + public @Nullable DiskInfo findDiskById(String id) { + Preconditions.checkNotNull(id); + // TODO; go directly to service to make this faster + for (DiskInfo disk : getDisks()) { + if (Objects.equals(disk.id, id)) { + return disk; + } + } + return null; + } + + /** {@hide} */ + public @Nullable VolumeInfo findVolumeById(String id) { + Preconditions.checkNotNull(id); + // TODO; go directly to service to make this faster + for (VolumeInfo vol : getVolumes()) { + if (Objects.equals(vol.id, id)) { + return vol; + } + } + return null; + } + + /** {@hide} */ + public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) { + Preconditions.checkNotNull(fsUuid); + // TODO; go directly to service to make this faster + for (VolumeInfo vol : getVolumes()) { + if (Objects.equals(vol.fsUuid, fsUuid)) { + return vol; + } + } + return null; + } + + /** {@hide} */ public @NonNull List<VolumeInfo> getVolumes() { try { return Arrays.asList(mMountService.getVolumes()); diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index c8c2f65..2dc0361 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -44,6 +44,7 @@ import java.io.File; * @hide */ public class VolumeInfo implements Parcelable { + /** Real volume representing internal emulated storage */ public static final String ID_EMULATED_INTERNAL = "emulated"; public static final int TYPE_PUBLIC = 0; diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index 7bdb4be..255f1fd 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -25,15 +25,16 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageParser.PackageLite; import android.os.Environment; -import android.os.Environment.UserEnvironment; import android.os.FileUtils; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.UserHandle; import android.os.storage.IMountService; import android.os.storage.StorageManager; import android.os.storage.StorageResultCode; +import android.os.storage.StorageVolume; +import android.os.storage.VolumeInfo; +import android.util.ArraySet; import android.util.Log; import libcore.io.IoUtils; @@ -335,6 +336,94 @@ public class PackageHelper { /** * Given a requested {@link PackageInfo#installLocation} and calculated + * install size, pick the actual volume to install the app. Only considers + * internal and private volumes, and prefers to keep an existing package on + * its current volume. + * + * @return the {@link VolumeInfo#fsUuid} to install onto, or {@code null} + * for internal storage. + */ + public static String resolveInstallVolume(Context context, String packageName, + int installLocation, long sizeBytes) throws IOException { + // TODO: handle existing apps installed in ASEC; currently assumes + // they'll end up back on internal storage + ApplicationInfo existingInfo = null; + try { + existingInfo = context.getPackageManager().getApplicationInfo(packageName, + PackageManager.GET_UNINSTALLED_PACKAGES); + } catch (NameNotFoundException ignored) { + } + + final StorageManager storageManager = context.getSystemService(StorageManager.class); + final boolean fitsOnInternal = fitsOnInternal(context, sizeBytes); + + final ArraySet<String> allCandidates = new ArraySet<>(); + VolumeInfo bestCandidate = null; + long bestCandidateAvailBytes = Long.MIN_VALUE; + for (VolumeInfo vol : storageManager.getVolumes()) { + if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.state == VolumeInfo.STATE_MOUNTED) { + final long availBytes = storageManager.getStorageBytesUntilLow(new File(vol.path)); + if (availBytes >= sizeBytes) { + allCandidates.add(vol.fsUuid); + } + if (availBytes >= bestCandidateAvailBytes) { + bestCandidate = vol; + bestCandidateAvailBytes = availBytes; + } + } + } + + // System apps always forced to internal storage + if (existingInfo != null && existingInfo.isSystemApp()) { + installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; + } + + // If app expresses strong desire for internal space, honor it + if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { + if (fitsOnInternal) { + return null; + } else { + throw new IOException("Requested internal only, but not enough space"); + } + } + + // If app already exists somewhere, prefer to stay on that volume + if (existingInfo != null) { + if (existingInfo.volumeUuid == null && fitsOnInternal) { + return null; + } + if (allCandidates.contains(existingInfo.volumeUuid)) { + return existingInfo.volumeUuid; + } + } + + // We're left with either preferring external or auto, so just pick + // volume with most space + if (bestCandidate != null) { + return bestCandidate.fsUuid; + } else if (fitsOnInternal) { + return null; + } else { + throw new IOException("No special requests, but no room anywhere"); + } + } + + public static boolean fitsOnInternal(Context context, long sizeBytes) { + final StorageManager storage = context.getSystemService(StorageManager.class); + final File target = Environment.getDataDirectory(); + return (sizeBytes <= storage.getStorageBytesUntilLow(target)); + } + + public static boolean fitsOnExternal(Context context, long sizeBytes) { + final StorageManager storage = context.getSystemService(StorageManager.class); + final StorageVolume primary = storage.getPrimaryVolume(); + return (sizeBytes > 0) && !primary.isEmulated() + && Environment.MEDIA_MOUNTED.equals(primary.getState()) + && sizeBytes <= storage.getStorageBytesUntilLow(primary.getPathFile()); + } + + /** + * Given a requested {@link PackageInfo#installLocation} and calculated * install size, pick the actual location to install the app. */ public static int resolveInstallLocation(Context context, String packageName, @@ -363,6 +452,7 @@ public class PackageHelper { } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) { // When app is already installed, prefer same medium if (existingInfo != null) { + // TODO: distinguish if this is external ASEC if ((existingInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { prefer = RECOMMEND_INSTALL_EXTERNAL; } else { @@ -377,30 +467,21 @@ public class PackageHelper { checkBoth = false; } - final boolean emulated = Environment.isExternalStorageEmulated(); - final StorageManager storage = StorageManager.from(context); - boolean fitsOnInternal = false; if (checkBoth || prefer == RECOMMEND_INSTALL_INTERNAL) { - final File target = Environment.getDataDirectory(); - fitsOnInternal = (sizeBytes <= storage.getStorageBytesUntilLow(target)); + fitsOnInternal = fitsOnInternal(context, sizeBytes); } boolean fitsOnExternal = false; - if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL)) { - final File target = new UserEnvironment(UserHandle.USER_OWNER) - .getExternalStorageDirectory(); - // External is only an option when size is known - if (sizeBytes > 0) { - fitsOnExternal = (sizeBytes <= storage.getStorageBytesUntilLow(target)); - } + if (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL) { + fitsOnExternal = fitsOnExternal(context, sizeBytes); } if (prefer == RECOMMEND_INSTALL_INTERNAL) { if (fitsOnInternal) { return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } - } else if (!emulated && prefer == RECOMMEND_INSTALL_EXTERNAL) { + } else if (prefer == RECOMMEND_INSTALL_EXTERNAL) { if (fitsOnExternal) { return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } @@ -409,22 +490,12 @@ public class PackageHelper { if (checkBoth) { if (fitsOnInternal) { return PackageHelper.RECOMMEND_INSTALL_INTERNAL; - } else if (!emulated && fitsOnExternal) { + } else if (fitsOnExternal) { return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } } - /* - * If they requested to be on the external media by default, return that - * the media was unavailable. Otherwise, indicate there was insufficient - * storage space available. - */ - if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL) - && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { - return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE; - } else { - return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; - } + return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; } public static long calculateInstalledSize(PackageLite pkg, boolean isForwardLocked, diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index 456f1fb..a341c95 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -833,6 +833,9 @@ class MountService extends IMountService.Stub vol.userId = UserHandle.USER_OWNER; mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); + } else if (vol.type == VolumeInfo.TYPE_PRIVATE) { + mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); + } else { Slog.d(TAG, "Skipping automatic mounting of " + vol); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 95d7a52..aafb7a9 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -63,6 +63,8 @@ import android.os.RemoteException; import android.os.SELinux; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.StorageManager; +import android.os.storage.VolumeInfo; import android.system.ErrnoException; import android.system.Os; import android.text.TextUtils; @@ -75,6 +77,8 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.Xml; +import libcore.io.IoUtils; + import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageHelper; import com.android.internal.util.FastXmlSerializer; @@ -82,8 +86,6 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.IoThread; import com.google.android.collect.Sets; -import libcore.io.IoUtils; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -131,6 +133,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { private static final String ATTR_ORIGINATING_URI = "originatingUri"; private static final String ATTR_REFERRER_URI = "referrerUri"; private static final String ATTR_ABI_OVERRIDE = "abiOverride"; + private static final String ATTR_VOLUME_UUID = "volumeUuid"; /** Automatically destroy sessions older than this */ private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS; @@ -141,9 +144,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub { private final Context mContext; private final PackageManagerService mPm; - private final AppOpsManager mAppOps; - private final File mStagingDir; + private AppOpsManager mAppOps; + private StorageManager mStorage; + private final HandlerThread mInstallThread; private final Handler mInstallHandler; @@ -186,12 +190,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } }; - public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) { + public PackageInstallerService(Context context, PackageManagerService pm) { mContext = context; mPm = pm; - mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); - - mStagingDir = stagingDir; mInstallThread = new HandlerThread(TAG); mInstallThread.start(); @@ -208,8 +209,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub { synchronized (mSessions) { readSessionsLocked(); + final File internalStagingDir = buildInternalStagingDir(); final ArraySet<File> unclaimedStages = Sets.newArraySet( - mStagingDir.listFiles(sStageFilter)); + internalStagingDir.listFiles(sStageFilter)); final ArraySet<File> unclaimedIcons = Sets.newArraySet( mSessionsDir.listFiles()); @@ -238,6 +240,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } } + public void systemReady() { + mAppOps = mContext.getSystemService(AppOpsManager.class); + mStorage = mContext.getSystemService(StorageManager.class); + } + public void onSecureContainersAvailable() { synchronized (mSessions) { final ArraySet<String> unclaimed = new ArraySet<>(); @@ -275,13 +282,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Deprecated - public File allocateInternalStageDirLegacy() throws IOException { + public File allocateStageDirLegacy(String volumeUuid) throws IOException { synchronized (mSessions) { try { final int sessionId = allocateSessionIdLocked(); mLegacySessions.put(sessionId, true); - final File stageDir = buildInternalStageDir(sessionId); - prepareInternalStageDir(stageDir); + final File stageDir = buildStageDir(volumeUuid, sessionId); + prepareStageDir(stageDir); return stageDir; } catch (IllegalStateException e) { throw new IOException(e); @@ -322,11 +329,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub { Slog.w(TAG, "Abandoning old session first created at " + session.createdMillis); valid = false; - } else if (session.stageDir != null - && !session.stageDir.exists()) { - Slog.w(TAG, "Abandoning internal session with missing stage " - + session.stageDir); - valid = false; } else { valid = true; } @@ -378,6 +380,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI); params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI); params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE); + params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID); final File appIconFile = buildAppIconFile(sessionId); if (appIconFile.exists()) { @@ -448,6 +451,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri); writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri); writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride); + writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid); // Persist app icon if changed since last written final File appIconFile = buildAppIconFile(session.sessionId); @@ -528,28 +532,40 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } } - if (params.mode == SessionParams.MODE_FULL_INSTALL - || params.mode == SessionParams.MODE_INHERIT_EXISTING) { + switch (params.mode) { + case SessionParams.MODE_FULL_INSTALL: + case SessionParams.MODE_INHERIT_EXISTING: + break; + default: + throw new IllegalArgumentException("Invalid install mode: " + params.mode); + } + + // If caller requested explicit location, sanity check it, otherwise + // resolve the best internal or adopted location. + if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { + if (!PackageHelper.fitsOnInternal(mContext, params.sizeBytes)) { + throw new IOException("No suitable internal storage available"); + } + + } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) { + if (!PackageHelper.fitsOnExternal(mContext, params.sizeBytes)) { + throw new IOException("No suitable external storage available"); + } + + } else { + // For now, installs to adopted media are treated as internal from + // an install flag point-of-view. + params.setInstallFlagsInternal(); + // Resolve best location for install, based on combination of // requested install flags, delta size, and manifest settings. final long ident = Binder.clearCallingIdentity(); try { - final int resolved = PackageHelper.resolveInstallLocation(mContext, - params.appPackageName, params.installLocation, params.sizeBytes, - params.installFlags); - - if (resolved == PackageHelper.RECOMMEND_INSTALL_INTERNAL) { - params.setInstallFlagsInternal(); - } else if (resolved == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { - params.setInstallFlagsExternal(); - } else { - throw new IOException("No storage with enough free space; res=" + resolved); - } + params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, + params.appPackageName, params.installLocation, params.sizeBytes); } finally { Binder.restoreCallingIdentity(ident); } - } else { - throw new IllegalArgumentException("Invalid install mode: " + params.mode); } final int sessionId; @@ -574,7 +590,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { File stageDir = null; String stageCid = null; if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { - stageDir = buildInternalStageDir(sessionId); + stageDir = buildStageDir(params.volumeUuid, sessionId); } else { stageCid = buildExternalStageCid(sessionId); } @@ -673,11 +689,30 @@ public class PackageInstallerService extends IPackageInstaller.Stub { throw new IllegalStateException("Failed to allocate session ID"); } - private File buildInternalStageDir(int sessionId) { - return new File(mStagingDir, "vmdl" + sessionId + ".tmp"); + private File buildInternalStagingDir() { + return new File(Environment.getDataDirectory(), "app"); + } + + private File buildStagingDir(String volumeUuid) throws FileNotFoundException { + if (volumeUuid == null) { + return buildInternalStagingDir(); + } else { + final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid); + if (vol != null && vol.type == VolumeInfo.TYPE_PRIVATE + && vol.state == VolumeInfo.STATE_MOUNTED) { + return new File(vol.path, "app"); + } else { + throw new FileNotFoundException("Failed to find volume for UUID " + volumeUuid); + } + } + } + + private File buildStageDir(String volumeUuid, int sessionId) throws FileNotFoundException { + final File stagingDir = buildStagingDir(volumeUuid); + return new File(stagingDir, "vmdl" + sessionId + ".tmp"); } - static void prepareInternalStageDir(File stageDir) throws IOException { + static void prepareStageDir(File stageDir) throws IOException { if (stageDir.exists()) { throw new IOException("Session dir already exists: " + stageDir); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index cc1b3ad..09e990c 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -25,7 +25,7 @@ import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDONLY; import static android.system.OsConstants.O_WRONLY; import static com.android.server.pm.PackageInstallerService.prepareExternalStageCid; -import static com.android.server.pm.PackageInstallerService.prepareInternalStageDir; +import static com.android.server.pm.PackageInstallerService.prepareStageDir; import android.content.Context; import android.content.Intent; @@ -61,6 +61,9 @@ import android.util.ExceptionUtils; import android.util.MathUtils; import android.util.Slog; +import libcore.io.IoUtils; +import libcore.io.Libcore; + import com.android.internal.annotations.GuardedBy; import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; @@ -69,9 +72,6 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter; -import libcore.io.IoUtils; -import libcore.io.Libcore; - import java.io.File; import java.io.FileDescriptor; import java.io.IOException; @@ -892,7 +892,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { synchronized (mLock) { if (!mPrepared) { if (stageDir != null) { - prepareInternalStageDir(stageDir); + prepareStageDir(stageDir); } else if (stageCid != null) { prepareExternalStageCid(stageCid, params.sizeBytes); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2ff1718..84dc748 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -43,11 +43,17 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIB 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; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; +import static android.content.pm.PackageManager.MOVE_EXTERNAL_MEDIA; +import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST; +import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING; +import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE; +import static android.content.pm.PackageManager.MOVE_INTERNAL; import static android.content.pm.PackageParser.isApkFile; import static android.os.Process.PACKAGE_INFO_GID; import static android.os.Process.SYSTEM_UID; @@ -65,31 +71,7 @@ import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet; import android.Manifest; -import android.content.pm.IntentFilterVerificationInfo; -import android.util.ArrayMap; - -import com.android.internal.R; -import com.android.internal.app.IMediaContainerService; -import com.android.internal.app.ResolverActivity; -import com.android.internal.content.NativeLibraryHelper; -import com.android.internal.content.PackageHelper; -import com.android.internal.os.IParcelFileDescriptorFactory; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.FastPrintWriter; -import com.android.internal.util.FastXmlSerializer; -import com.android.internal.util.IndentingPrintWriter; -import com.android.server.EventLogTags; -import com.android.server.IntentResolver; -import com.android.server.LocalServices; -import com.android.server.ServiceThread; -import com.android.server.SystemConfig; -import com.android.server.Watchdog; -import com.android.server.pm.Settings.DatabaseVersion; -import com.android.server.storage.DeviceStorageMonitorInternal; - import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlSerializer; - import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.AppGlobals; @@ -119,6 +101,7 @@ import android.content.pm.IPackageManager; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; import android.content.pm.InstrumentationInfo; +import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.KeySet; import android.content.pm.ManifestDigest; import android.content.pm.PackageCleanItem; @@ -127,10 +110,10 @@ import android.content.pm.PackageInfoLite; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManager.LegacyPackageDeleteObserver; +import android.content.pm.PackageParser; import android.content.pm.PackageParser.ActivityIntentInfo; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; -import android.content.pm.PackageParser; import android.content.pm.PackageStats; import android.content.pm.PackageUserState; import android.content.pm.ParceledListSlice; @@ -150,13 +133,9 @@ import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.Debug; import android.os.Environment; import android.os.Environment.UserEnvironment; -import android.os.storage.IMountService; -import android.os.storage.StorageEventListener; -import android.os.storage.StorageManager; -import android.os.storage.VolumeInfo; -import android.os.Debug; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; @@ -172,6 +151,10 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.IMountService; +import android.os.storage.StorageEventListener; +import android.os.storage.StorageManager; +import android.os.storage.VolumeInfo; import android.security.KeyStore; import android.security.SystemKeyStore; import android.system.ErrnoException; @@ -179,6 +162,7 @@ import android.system.Os; import android.system.StructStat; import android.text.TextUtils; import android.text.format.DateUtils; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.DisplayMetrics; @@ -193,6 +177,33 @@ import android.util.SparseBooleanArray; import android.util.Xml; import android.view.Display; +import dalvik.system.DexFile; +import dalvik.system.VMRuntime; + +import libcore.io.IoUtils; +import libcore.util.EmptyArray; + +import com.android.internal.R; +import com.android.internal.app.IMediaContainerService; +import com.android.internal.app.ResolverActivity; +import com.android.internal.content.NativeLibraryHelper; +import com.android.internal.content.PackageHelper; +import com.android.internal.os.IParcelFileDescriptorFactory; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.IndentingPrintWriter; +import com.android.server.EventLogTags; +import com.android.server.IntentResolver; +import com.android.server.LocalServices; +import com.android.server.ServiceThread; +import com.android.server.SystemConfig; +import com.android.server.Watchdog; +import com.android.server.pm.Settings.DatabaseVersion; +import com.android.server.storage.DeviceStorageMonitorInternal; + +import org.xmlpull.v1.XmlSerializer; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; @@ -227,12 +238,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; -import dalvik.system.DexFile; -import dalvik.system.VMRuntime; - -import libcore.io.IoUtils; -import libcore.util.EmptyArray; - /** * Keep track of all those .apks everywhere. * @@ -1539,9 +1544,14 @@ public class PackageManagerService extends IPackageManager.Stub { private StorageEventListener mStorageListener = new StorageEventListener() { @Override public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { - Slog.v(TAG, vol.toString()); + if (vol.type == VolumeInfo.TYPE_PRIVATE) { + if (vol.state == VolumeInfo.STATE_MOUNTED) { + loadPrivatePackages(vol); + } else if (vol.state == VolumeInfo.STATE_UNMOUNTING) { + unloadPrivatePackages(vol); + } + } - // TODO: when private volume shows up, look for packages there too if (vol.isPrimary() && vol.type == VolumeInfo.TYPE_PUBLIC) { if (vol.state == VolumeInfo.STATE_MOUNTED) { updateExternalMediaStatus(true, false); @@ -2160,7 +2170,7 @@ public class PackageManagerService extends IPackageManager.Stub { mRequiredVerifierPackage = getRequiredVerifierLPr(); - mInstallerService = new PackageInstallerService(context, this, mAppInstallDir); + mInstallerService = new PackageInstallerService(context, this); mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr(); mIntentFilterVerifier = new IntentVerifierProxy(mContext, @@ -8476,8 +8486,8 @@ public class PackageManagerService extends IPackageManager.Stub { public void installPackage(String originPath, IPackageInstallObserver2 observer, int installFlags, String installerPackageName, VerificationParams verificationParams, String packageAbiOverride) { - installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams, - packageAbiOverride, UserHandle.getCallingUserId()); + installPackageAsUser(originPath, observer, installFlags, installerPackageName, + verificationParams, packageAbiOverride, UserHandle.getCallingUserId()); } @Override @@ -8524,7 +8534,7 @@ public class PackageManagerService extends IPackageManager.Stub { final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(origin, observer, installFlags, - installerPackageName, verificationParams, user, packageAbiOverride); + installerPackageName, null, verificationParams, user, packageAbiOverride); mHandler.sendMessage(msg); } @@ -8543,7 +8553,7 @@ public class PackageManagerService extends IPackageManager.Stub { final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(origin, observer, params.installFlags, - installerPackageName, verifParams, user, params.abiOverride); + installerPackageName, params.volumeUuid, verifParams, user, params.abiOverride); mHandler.sendMessage(msg); } @@ -9345,19 +9355,21 @@ public class PackageManagerService extends IPackageManager.Stub { final IPackageInstallObserver2 observer; int installFlags; final String installerPackageName; + final String volumeUuid; final VerificationParams verificationParams; private InstallArgs mArgs; private int mRet; final String packageAbiOverride; InstallParams(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags, - String installerPackageName, VerificationParams verificationParams, UserHandle user, - String packageAbiOverride) { + String installerPackageName, String volumeUuid, + VerificationParams verificationParams, UserHandle user, String packageAbiOverride) { super(user); this.origin = origin; this.observer = observer; this.installFlags = installFlags; this.installerPackageName = installerPackageName; + this.volumeUuid = volumeUuid; this.verificationParams = verificationParams; this.packageAbiOverride = packageAbiOverride; } @@ -9711,7 +9723,7 @@ public class PackageManagerService extends IPackageManager.Stub { * @param installFlags package installation flags * @return true if should be installed on external storage */ - private static boolean installOnSd(int installFlags) { + private static boolean installOnExternalAsec(int installFlags) { if ((installFlags & PackageManager.INSTALL_INTERNAL) != 0) { return false; } @@ -9732,7 +9744,7 @@ public class PackageManagerService extends IPackageManager.Stub { } private InstallArgs createInstallArgs(InstallParams params) { - if (installOnSd(params.installFlags) || params.isForwardLocked()) { + if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) { return new AsecInstallArgs(params); } else { return new FileInstallArgs(params); @@ -9746,7 +9758,7 @@ public class PackageManagerService extends IPackageManager.Stub { private InstallArgs createInstallArgsForExisting(int installFlags, String codePath, String resourcePath, String nativeLibraryRoot, String[] instructionSets) { final boolean isInAsec; - if (installOnSd(installFlags)) { + if (installOnExternalAsec(installFlags)) { /* Apps on SD card are always in ASEC containers. */ isInAsec = true; } else if (installForwardLocked(installFlags) @@ -9762,7 +9774,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (isInAsec) { return new AsecInstallArgs(codePath, instructionSets, - installOnSd(installFlags), installForwardLocked(installFlags)); + installOnExternalAsec(installFlags), installForwardLocked(installFlags)); } else { return new FileInstallArgs(codePath, resourcePath, nativeLibraryRoot, instructionSets); @@ -9777,6 +9789,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Always refers to PackageManager flags only final int installFlags; final String installerPackageName; + final String volumeUuid; final ManifestDigest manifestDigest; final UserHandle user; final String abiOverride; @@ -9787,12 +9800,13 @@ public class PackageManagerService extends IPackageManager.Stub { /* nullable */ String[] instructionSets; InstallArgs(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags, - String installerPackageName, ManifestDigest manifestDigest, UserHandle user, - String[] instructionSets, String abiOverride) { + String installerPackageName, String volumeUuid, ManifestDigest manifestDigest, + UserHandle user, String[] instructionSets, String abiOverride) { this.origin = origin; this.installFlags = installFlags; this.observer = observer; this.installerPackageName = installerPackageName; + this.volumeUuid = volumeUuid; this.manifestDigest = manifestDigest; this.user = user; this.instructionSets = instructionSets; @@ -9844,7 +9858,7 @@ public class PackageManagerService extends IPackageManager.Stub { return (installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0; } - protected boolean isExternal() { + protected boolean isExternalAsec() { return (installFlags & PackageManager.INSTALL_EXTERNAL) != 0; } @@ -9891,8 +9905,8 @@ public class PackageManagerService extends IPackageManager.Stub { /** New install */ FileInstallArgs(InstallParams params) { super(params.origin, params.observer, params.installFlags, - params.installerPackageName, params.getManifestDigest(), params.getUser(), - null /* instruction sets */, params.packageAbiOverride); + params.installerPackageName, params.volumeUuid, params.getManifestDigest(), + params.getUser(), null /* instruction sets */, params.packageAbiOverride); if (isFwdLocked()) { throw new IllegalArgumentException("Forward locking only supported in ASEC"); } @@ -9901,7 +9915,7 @@ public class PackageManagerService extends IPackageManager.Stub { /** Existing install */ FileInstallArgs(String codePath, String resourcePath, String legacyNativeLibraryPath, String[] instructionSets) { - super(OriginInfo.fromNothing(), null, 0, null, null, null, instructionSets, null); + super(OriginInfo.fromNothing(), null, 0, null, null, null, null, instructionSets, null); this.codeFile = (codePath != null) ? new File(codePath) : null; this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null; this.legacyNativeLibraryPath = (legacyNativeLibraryPath != null) ? @@ -9925,7 +9939,7 @@ public class PackageManagerService extends IPackageManager.Stub { } try { - final File tempDir = mInstallerService.allocateInternalStageDirLegacy(); + final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid); codeFile = tempDir; resourceFile = tempDir; } catch (IOException e) { @@ -9986,8 +10000,9 @@ public class PackageManagerService extends IPackageManager.Stub { cleanUp(); return false; } else { + final File targetDir = codeFile.getParentFile(); final File beforeCodeFile = codeFile; - final File afterCodeFile = getNextCodePath(pkg.packageName); + final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName); Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile); try { @@ -10137,16 +10152,15 @@ public class PackageManagerService extends IPackageManager.Stub { /** New install */ AsecInstallArgs(InstallParams params) { super(params.origin, params.observer, params.installFlags, - params.installerPackageName, params.getManifestDigest(), - params.getUser(), null /* instruction sets */, - params.packageAbiOverride); + params.installerPackageName, params.volumeUuid, params.getManifestDigest(), + params.getUser(), null /* instruction sets */, params.packageAbiOverride); } /** Existing install */ AsecInstallArgs(String fullCodePath, String[] instructionSets, boolean isExternal, boolean isForwardLocked) { super(OriginInfo.fromNothing(), null, (isExternal ? INSTALL_EXTERNAL : 0) - | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, + | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null, instructionSets, null); // Hackily pretend we're still looking at a full code path if (!fullCodePath.endsWith(RES_FILE_NAME)) { @@ -10163,7 +10177,7 @@ public class PackageManagerService extends IPackageManager.Stub { AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) { super(OriginInfo.fromNothing(), null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0) - | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, + | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null, instructionSets, null); this.cid = cid; setMountPath(PackageHelper.getSdDir(cid)); @@ -10178,7 +10192,7 @@ public class PackageManagerService extends IPackageManager.Stub { abiOverride); final File target; - if (isExternal()) { + if (isExternalAsec()) { target = new UserEnvironment(UserHandle.USER_OWNER).getExternalStorageDirectory(); } else { target = Environment.getDataDirectory(); @@ -10207,7 +10221,7 @@ public class PackageManagerService extends IPackageManager.Stub { } final String newMountPath = imcs.copyPackageToContainer( - origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternal(), + origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternalAsec(), isFwdLocked(), deriveAbiOverride(abiOverride, null /* settings */)); if (newMountPath != null) { @@ -10488,11 +10502,11 @@ public class PackageManagerService extends IPackageManager.Stub { return prefix + idxStr; } - private File getNextCodePath(String packageName) { + private File getNextCodePath(File targetDir, String packageName) { int suffix = 1; File result; do { - result = new File(mAppInstallDir, packageName + "-" + suffix); + result = new File(targetDir, packageName + "-" + suffix); suffix++; } while (result.exists()); return result; @@ -10556,9 +10570,9 @@ public class PackageManagerService extends IPackageManager.Stub { /* * Install a non-existing package. */ - private void installNewPackageLI(PackageParser.Package pkg, - int parseFlags, int scanFlags, UserHandle user, - String installerPackageName, PackageInstalledInfo res) { + private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags, + UserHandle user, String installerPackageName, String volumeUuid, + PackageInstalledInfo res) { // Remember this for later, in case we need to rollback this install String pkgName = pkg.packageName; @@ -10587,7 +10601,7 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags, System.currentTimeMillis(), user); - updateSettingsLI(newPackage, installerPackageName, null, null, res, user); + updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user); // delete the partially installed application. the data directory will have to be // restored if it was already existing if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) { @@ -10619,9 +10633,9 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } - private void replacePackageLI(PackageParser.Package pkg, - int parseFlags, int scanFlags, UserHandle user, - String installerPackageName, PackageInstalledInfo res) { + private void replacePackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags, + UserHandle user, String installerPackageName, String volumeUuid, + PackageInstalledInfo res) { PackageParser.Package oldPackage; String pkgName = pkg.packageName; int[] allUsers; @@ -10660,17 +10674,17 @@ public class PackageManagerService extends IPackageManager.Stub { boolean sysPkg = (isSystemApp(oldPackage)); if (sysPkg) { replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags, - user, allUsers, perUserInstalled, installerPackageName, res); + user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res); } else { replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags, - user, allUsers, perUserInstalled, installerPackageName, res); + user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res); } } private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage, PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user, - int[] allUsers, boolean[] perUserInstalled, - String installerPackageName, PackageInstalledInfo res) { + int[] allUsers, boolean[] perUserInstalled, String installerPackageName, + String volumeUuid, PackageInstalledInfo res) { String pkgName = deletedPackage.packageName; boolean deletedPkg = true; boolean updatedSettings = false; @@ -10709,8 +10723,8 @@ public class PackageManagerService extends IPackageManager.Stub { try { final PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user); - updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res, - user); + updateSettingsLI(newPackage, installerPackageName, volumeUuid, allUsers, + perUserInstalled, res, user); updatedSettings = true; } catch (PackageManagerException e) { res.setError("Package couldn't be installed in " + pkg.codePath, e); @@ -10735,10 +10749,10 @@ public class PackageManagerService extends IPackageManager.Stub { if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage); File restoreFile = new File(deletedPackage.codePath); // Parse old package - boolean oldOnSd = isExternal(deletedPackage); + boolean oldExternal = isExternal(deletedPackage); int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY | (deletedPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0) | - (oldOnSd ? PackageParser.PARSE_ON_SDCARD : 0); + (oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0); int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME; try { scanPackageLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime, null); @@ -10762,8 +10776,8 @@ public class PackageManagerService extends IPackageManager.Stub { private void replaceSystemPackageLI(PackageParser.Package deletedPackage, PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user, - int[] allUsers, boolean[] perUserInstalled, - String installerPackageName, PackageInstalledInfo res) { + int[] allUsers, boolean[] perUserInstalled, String installerPackageName, + String volumeUuid, PackageInstalledInfo res) { if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg + ", old=" + deletedPackage); boolean disabledSystem = false; @@ -10840,8 +10854,8 @@ public class PackageManagerService extends IPackageManager.Stub { } if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { - updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res, - user); + updateSettingsLI(newPackage, installerPackageName, volumeUuid, allUsers, + perUserInstalled, res, user); updatedSettings = true; } @@ -10876,8 +10890,8 @@ public class PackageManagerService extends IPackageManager.Stub { } private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName, - int[] allUsers, boolean[] perUserInstalled, - PackageInstalledInfo res, UserHandle user) { + String volumeUuid, int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res, + UserHandle user) { String pkgName = newPackage.packageName; synchronized (mPackages) { //write settings. the installStatus will be incomplete at this stage. @@ -10935,6 +10949,7 @@ public class PackageManagerService extends IPackageManager.Stub { res.pkg = newPackage; mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE); mSettings.setInstallerPackageName(pkgName, installerPackageName); + mSettings.setVolumeUuid(pkgName, volumeUuid); res.returnCode = PackageManager.INSTALL_SUCCEEDED; //to update install status mSettings.writeLPr(); @@ -10943,10 +10958,12 @@ public class PackageManagerService extends IPackageManager.Stub { private void installPackageLI(InstallArgs args, PackageInstalledInfo res) { final int installFlags = args.installFlags; - String installerPackageName = args.installerPackageName; - File tmpPackageFile = new File(args.getCodePath()); - boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0); - boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0); + final String installerPackageName = args.installerPackageName; + final String volumeUuid = args.volumeUuid; + final File tmpPackageFile = new File(args.getCodePath()); + final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0); + final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0) + || (args.volumeUuid != null)); boolean replace = false; final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE; // Result object to be returned @@ -10956,7 +10973,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Retrieve PackageSettings and parse package final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) - | (onSd ? PackageParser.PARSE_ON_SDCARD : 0); + | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0); PackageParser pp = new PackageParser(); pp.setSeparateProcesses(mSeparateProcesses); pp.setDisplayMetrics(mMetrics); @@ -11108,7 +11125,7 @@ public class PackageManagerService extends IPackageManager.Stub { } - if (systemApp && onSd) { + if (systemApp && onExternal) { // Disable updates to system apps on sdcard res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION, "Cannot install updates to system apps on sdcard"); @@ -11134,10 +11151,10 @@ public class PackageManagerService extends IPackageManager.Stub { if (replace) { // Call replacePackageLI with SCAN_NO_DEX, since we already made dexopt replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING | SCAN_NO_DEX, args.user, - installerPackageName, res); + installerPackageName, volumeUuid, res); } else { installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES, - args.user, installerPackageName, res); + args.user, installerPackageName, volumeUuid, res); } synchronized (mPackages) { final PackageSetting ps = mSettings.mPackages.get(pkgName); @@ -11265,7 +11282,9 @@ public class PackageManagerService extends IPackageManager.Stub { private int packageFlagsToInstallFlags(PackageSetting ps) { int installFlags = 0; - if (isExternal(ps)) { + if (isExternal(ps) && TextUtils.isEmpty(ps.volumeUuid)) { + // This existing package was an external ASEC install when we have + // the external flag without a UUID installFlags |= PackageManager.INSTALL_EXTERNAL; } if (ps.isForwardLocked()) { @@ -12975,6 +12994,8 @@ public class PackageManagerService extends IPackageManager.Stub { // Watch for external volumes that come and go over time final StorageManager storage = mContext.getSystemService(StorageManager.class); storage.registerListener(mStorageListener); + + mInstallerService.systemReady(); } @Override @@ -13713,13 +13734,32 @@ public class PackageManagerService extends IPackageManager.Stub { } private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, + ArrayList<ApplicationInfo> infos, IIntentReceiver finishedReceiver) { + final int size = infos.size(); + final String[] packageNames = new String[size]; + final int[] packageUids = new int[size]; + for (int i = 0; i < size; i++) { + final ApplicationInfo info = infos.get(i); + packageNames[i] = info.packageName; + packageUids[i] = info.uid; + } + sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids, + finishedReceiver); + } + + private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) { - int size = pkgList.size(); + sendResourcesChangedBroadcast(mediaStatus, replacing, + pkgList.toArray(new String[pkgList.size()]), uidArr, finishedReceiver); + } + + private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, + String[] pkgList, int uidArr[], IIntentReceiver finishedReceiver) { + int size = pkgList.length; if (size > 0) { // Send broadcasts here Bundle extras = new Bundle(); - extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList - .toArray(new String[size])); + extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList); if (uidArr != null) { extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr); } @@ -13762,8 +13802,8 @@ public class PackageManagerService extends IPackageManager.Stub { } // Parse package int parseFlags = mDefParseFlags; - if (args.isExternal()) { - parseFlags |= PackageParser.PARSE_ON_SDCARD; + if (args.isExternalAsec()) { + parseFlags |= PackageParser.PARSE_EXTERNAL_STORAGE; } if (args.isFwdLocked()) { parseFlags |= PackageParser.PARSE_FORWARD_LOCK; @@ -13910,73 +13950,130 @@ public class PackageManagerService extends IPackageManager.Stub { } } - /** Binder call */ + private void loadPrivatePackages(VolumeInfo vol) { + final ArrayList<ApplicationInfo> loaded = new ArrayList<>(); + final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE; + synchronized (mPackages) { + final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid); + for (PackageSetting ps : packages) { + synchronized (mInstallLock) { + final PackageParser.Package pkg; + try { + pkg = scanPackageLI(ps.codePath, parseFlags, 0, 0, null); + loaded.add(pkg.applicationInfo); + } catch (PackageManagerException e) { + Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage()); + } + } + } + + // TODO: regrant any permissions that changed based since original install + + mSettings.writeLPr(); + } + + Slog.d(TAG, "Loaded packages " + loaded); + sendResourcesChangedBroadcast(true, false, loaded, null); + } + + private void unloadPrivatePackages(VolumeInfo vol) { + final ArrayList<ApplicationInfo> unloaded = new ArrayList<>(); + synchronized (mPackages) { + final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid); + for (PackageSetting ps : packages) { + if (ps.pkg == null) continue; + synchronized (mInstallLock) { + final ApplicationInfo info = ps.pkg.applicationInfo; + final PackageRemovedInfo outInfo = new PackageRemovedInfo(); + if (deletePackageLI(ps.name, null, false, null, null, + PackageManager.DELETE_KEEP_DATA, outInfo, false)) { + unloaded.add(info); + } else { + Slog.w(TAG, "Failed to unload " + ps.codePath); + } + } + } + + mSettings.writeLPr(); + } + + Slog.d(TAG, "Unloaded packages " + unloaded); + sendResourcesChangedBroadcast(false, false, unloaded, null); + } + @Override public void movePackage(final String packageName, final IPackageMoveObserver observer, final int flags) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null); - UserHandle user = new UserHandle(UserHandle.getCallingUserId()); - int returnCode = PackageManager.MOVE_SUCCEEDED; - int currInstallFlags = 0; - int newInstallFlags = 0; + + final int installFlags; + if ((flags & MOVE_INTERNAL) != 0) { + installFlags = INSTALL_INTERNAL; + } else if ((flags & MOVE_EXTERNAL_MEDIA) != 0) { + installFlags = INSTALL_EXTERNAL; + } else { + throw new IllegalArgumentException("Unsupported move flags " + flags); + } + + try { + movePackageInternal(packageName, null, installFlags, false, observer); + } catch (PackageManagerException e) { + Slog.d(TAG, "Failed to move " + packageName, e); + try { + observer.packageMoved(packageName, e.error); + } catch (RemoteException ignored) { + } + } + } + + @Override + public void movePackageAndData(final String packageName, final String volumeUuid, + final IPackageMoveObserver observer) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null); + try { + movePackageInternal(packageName, volumeUuid, INSTALL_INTERNAL, true, observer); + } catch (PackageManagerException e) { + Slog.d(TAG, "Failed to move " + packageName, e); + try { + observer.packageMoved(packageName, e.error); + } catch (RemoteException ignored) { + } + } + } + + private void movePackageInternal(final String packageName, String volumeUuid, int installFlags, + boolean andData, final IPackageMoveObserver observer) throws PackageManagerException { + final UserHandle user = new UserHandle(UserHandle.getCallingUserId()); File codeFile = null; String installerPackageName = null; String packageAbiOverride = null; + // TOOD: move app private data before installing + // reader synchronized (mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); final PackageSetting ps = mSettings.mPackages.get(packageName); if (pkg == null || ps == null) { - returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST; - } else { - // Disable moving fwd locked apps and system packages - if (pkg.applicationInfo != null && isSystemApp(pkg)) { - Slog.w(TAG, "Cannot move system application"); - returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE; - } else if (pkg.mOperationPending) { - Slog.w(TAG, "Attempt to move package which has pending operations"); - returnCode = PackageManager.MOVE_FAILED_OPERATION_PENDING; - } else { - // Find install location first - if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 - && (flags & PackageManager.MOVE_INTERNAL) != 0) { - Slog.w(TAG, "Ambigous flags specified for move location."); - returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION; - } else { - newInstallFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 - ? PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL; - currInstallFlags = isExternal(pkg) - ? PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL; - - if (newInstallFlags == currInstallFlags) { - Slog.w(TAG, "No move required. Trying to move to same location"); - returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION; - } else { - if (pkg.isForwardLocked()) { - currInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK; - newInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK; - } - } - } - if (returnCode == PackageManager.MOVE_SUCCEEDED) { - pkg.mOperationPending = true; - } - } - - codeFile = new File(pkg.codePath); - installerPackageName = ps.installerPackageName; - packageAbiOverride = ps.cpuAbiOverrideString; + throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package"); } - } - if (returnCode != PackageManager.MOVE_SUCCEEDED) { - try { - observer.packageMoved(packageName, returnCode); - } catch (RemoteException ignored) { + if (pkg.applicationInfo.isSystemApp()) { + throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE, + "Cannot move system application"); + } else if (pkg.mOperationPending) { + throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING, + "Attempt to move package which has pending operations"); } - return; + + // TODO: yell if already in desired location + + pkg.mOperationPending = true; + + codeFile = new File(pkg.codePath); + installerPackageName = ps.installerPackageName; + packageAbiOverride = ps.cpuAbiOverrideString; } final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() { @@ -14018,12 +14115,12 @@ public class PackageManagerService extends IPackageManager.Stub { // Treat a move like reinstalling an existing app, which ensures that we // process everythign uniformly, like unpacking native libraries. - newInstallFlags |= PackageManager.INSTALL_REPLACE_EXISTING; + installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; final Message msg = mHandler.obtainMessage(INIT_COPY); final OriginInfo origin = OriginInfo.fromExistingFile(codeFile); - msg.obj = new InstallParams(origin, installObserver, newInstallFlags, - installerPackageName, null, user, packageAbiOverride); + msg.obj = new InstallParams(origin, installObserver, installFlags, + installerPackageName, volumeUuid, null, user, packageAbiOverride); mHandler.sendMessage(msg); } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index daa6d64..f294b32 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -23,6 +23,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageUserState; +import android.os.storage.VolumeInfo; import android.util.ArraySet; import android.util.SparseArray; @@ -108,8 +109,10 @@ abstract class PackageSettingBase extends SettingBase { PackageSettingBase origPackage; - /* package name of the app that installed this package */ + /** Package name of the app that installed this package */ String installerPackageName; + /** UUID of {@link VolumeInfo} hosting this app */ + String volumeUuid; IntentFilterVerificationInfo verificationInfo; @@ -161,6 +164,7 @@ abstract class PackageSettingBase extends SettingBase { origPackage = base.origPackage; installerPackageName = base.installerPackageName; + volumeUuid = base.volumeUuid; keySetData = new PackageKeySetData(base.keySetData); } @@ -183,10 +187,18 @@ abstract class PackageSettingBase extends SettingBase { installerPackageName = packageName; } - String getInstallerPackageName() { + public String getInstallerPackageName() { return installerPackageName; } + public void setVolumeUuid(String volumeUuid) { + this.volumeUuid = volumeUuid; + } + + public String getVolumeUuid() { + return volumeUuid; + } + public void setInstallStatus(int newStatus) { installStatus = newStatus; } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 6930965..6b7c35c 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -42,6 +42,7 @@ import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.VolumeInfo; import android.util.AtomicFile; import android.text.TextUtils; import android.util.LogPrinter; @@ -53,6 +54,7 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; +import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.backup.PreferredActivityBackupHelper; import com.android.server.pm.PackageManagerService.DumpState; @@ -333,14 +335,20 @@ final class Settings { } } - void setInstallerPackageName(String pkgName, - String installerPkgName) { + void setInstallerPackageName(String pkgName, String installerPkgName) { PackageSetting p = mPackages.get(pkgName); - if(p != null) { + if (p != null) { p.setInstallerPackageName(installerPkgName); } } + void setVolumeUuid(String pkgName, String volumeUuid) { + PackageSetting p = mPackages.get(pkgName); + if (p != null) { + p.setVolumeUuid(volumeUuid); + } + } + SharedUserSetting getSharedUserLPw(String name, int pkgFlags, int pkgPrivateFlags, boolean create) { SharedUserSetting s = mSharedUsers.get(name); @@ -2066,6 +2074,9 @@ final class Settings { if (pkg.installerPackageName != null) { serializer.attribute(null, "installer", pkg.installerPackageName); } + if (pkg.volumeUuid != null) { + serializer.attribute(null, "volumeUuid", pkg.volumeUuid); + } pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); if ((pkg.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) { writePermissionsLPr(serializer, pkg.getPermissionsState().getInstallPermissions()); @@ -2908,6 +2919,7 @@ final class Settings { String cpuAbiOverrideString = null; String systemStr = null; String installerPackageName = null; + String volumeUuid = null; String uidError = null; int pkgFlags = 0; int pkgPrivateFlags = 0; @@ -2945,6 +2957,7 @@ final class Settings { } } installerPackageName = parser.getAttributeValue(null, "installer"); + volumeUuid = parser.getAttributeValue(null, "volumeUuid"); systemStr = parser.getAttributeValue(null, "publicFlags"); if (systemStr != null) { @@ -3093,6 +3106,7 @@ final class Settings { if (packageSetting != null) { packageSetting.uidError = "true".equals(uidError); packageSetting.installerPackageName = installerPackageName; + packageSetting.volumeUuid = volumeUuid; packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr; packageSetting.primaryCpuAbiString = primaryCpuAbiString; packageSetting.secondaryCpuAbiString = secondaryCpuAbiString; @@ -3549,6 +3563,22 @@ final class Settings { return null; } + /** + * Return all {@link PackageSetting} that are actively installed on the + * given {@link VolumeInfo#fsUuid}. + */ + List<PackageSetting> getVolumePackagesLPr(String volumeUuid) { + Preconditions.checkNotNull(volumeUuid); + ArrayList<PackageSetting> res = new ArrayList<>(); + for (int i = 0; i < mPackages.size(); i++) { + final PackageSetting setting = mPackages.valueAt(i); + if (Objects.equals(volumeUuid, setting.volumeUuid)) { + res.add(setting); + } + } + return res; + } + static void printFlags(PrintWriter pw, int val, Object[] spec) { pw.print("[ "); for (int i=0; i<spec.length; i+=2) { @@ -3755,6 +3785,10 @@ final class Settings { pw.print(prefix); pw.print(" installerPackageName="); pw.println(ps.installerPackageName); } + if (ps.volumeUuid != null) { + pw.print(prefix); pw.print(" volumeUuid="); + pw.println(ps.volumeUuid); + } pw.print(prefix); pw.print(" signatures="); pw.println(ps.signatures); pw.print(prefix); pw.print(" installPermissionsFixed="); pw.print(ps.installPermissionsFixed); diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index a204376..c8b6846 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -485,14 +485,19 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } - /** - * @hide - to match hiding in superclass - */ + /** {@hide} */ @Override public void movePackage(String packageName, IPackageMoveObserver observer, int flags) { throw new UnsupportedOperationException(); } + /** {@hide} */ + @Override + public void movePackageAndData(String packageName, String volumeUuid, + IPackageMoveObserver observer) { + throw new UnsupportedOperationException(); + } + @Override public String getInstallerPackageName(String packageName) { throw new UnsupportedOperationException(); |