summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/PackageManagerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/PackageManagerService.java')
-rw-r--r--services/java/com/android/server/PackageManagerService.java505
1 files changed, 392 insertions, 113 deletions
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 4326efc..252f2a6 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -44,6 +44,7 @@ import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageManager;
+import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
@@ -142,6 +143,9 @@ class PackageManagerService extends IPackageManager.Stub {
FileObserver.CLOSE_WRITE /*| FileObserver.CREATE*/ | FileObserver.MOVED_TO;
private static final int OBSERVER_EVENTS = REMOVE_EVENTS | ADD_EVENTS;
+ // Suffix used during package installation when copying/moving
+ // package apks to install directory.
+ private static final String INSTALL_PACKAGE_SUFFIX = "-";
static final int SCAN_MONITOR = 1<<0;
static final int SCAN_NO_DEX = 1<<1;
@@ -321,8 +325,8 @@ class PackageManagerService extends IPackageManager.Stub {
};
class PackageHandler extends Handler {
- final ArrayList<InstallParams> mPendingInstalls =
- new ArrayList<InstallParams>();
+ final ArrayList<HandlerParams> mPendingInstalls =
+ new ArrayList<HandlerParams>();
// Service Connection to remote media container service to copy
// package uri's from external media onto secure containers
// or internal storage.
@@ -334,20 +338,19 @@ class PackageManagerService extends IPackageManager.Stub {
public void handleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
- InstallParams params = (InstallParams) msg.obj;
+ HandlerParams params = (HandlerParams) msg.obj;
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
if (mContainerService != null) {
// No need to add to pending list. Use remote stub directly
- handleStartCopy(params);
+ params.handleStartCopy(mContainerService);
} else {
if (mContext.bindService(service, mDefContainerConn,
Context.BIND_AUTO_CREATE)) {
mPendingInstalls.add(params);
} else {
Log.e(TAG, "Failed to bind to media container service");
- // Indicate install failure TODO add new error code
- processPendingInstall(createInstallArgs(params),
- PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
+ // Indicate service bind error
+ params.handleServiceError();
}
}
break;
@@ -358,9 +361,9 @@ class PackageManagerService extends IPackageManager.Stub {
mContainerService = (IMediaContainerService) msg.obj;
}
if (mPendingInstalls.size() > 0) {
- InstallParams params = mPendingInstalls.remove(0);
+ HandlerParams params = mPendingInstalls.remove(0);
if (params != null) {
- handleStartCopy(params);
+ params.handleStartCopy(mContainerService);
}
}
break;
@@ -421,54 +424,6 @@ class PackageManagerService extends IPackageManager.Stub {
} break;
}
}
-
- // Utility method to initiate copying apk via media
- // container service.
- private void handleStartCopy(InstallParams params) {
- int ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- if (mContainerService != null) {
- // Remote call to find out default install location
- int loc = params.getInstallLocation(mContainerService);
- // Use install location to create InstallArgs and temporary
- // install location
- if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE){
- ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
- ret = PackageManager.INSTALL_FAILED_INVALID_APK;
- } else {
- if ((params.flags & PackageManager.INSTALL_EXTERNAL) == 0){
- if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
- // Set the flag to install on external media.
- params.flags |= PackageManager.INSTALL_EXTERNAL;
- } else {
- // Make sure the flag for installing on external
- // media is unset
- params.flags &= ~PackageManager.INSTALL_EXTERNAL;
- }
- }
- // Disable forward locked apps on sdcard.
- if ((params.flags & PackageManager.INSTALL_FORWARD_LOCK) != 0 &&
- (params.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
- // Make sure forward locked apps can only be installed
- // on internal storage
- Log.w(TAG, "Cannot install protected apps on sdcard");
- ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
- } else {
- ret = PackageManager.INSTALL_SUCCEEDED;
- }
- }
- }
- mHandler.sendEmptyMessage(MCS_UNBIND);
- // Create the file args now.
- InstallArgs args = createInstallArgs(params);
- if (ret == PackageManager.INSTALL_SUCCEEDED) {
- // Create copy only if we are not in an erroneous state.
- args.createCopyFile();
- // Remote call to initiate copy
- ret = args.copyApk(mContainerService);
- }
- processPendingInstall(args, ret);
- }
}
static boolean installOnSd(int flags) {
@@ -2180,8 +2135,8 @@ class PackageManagerService extends IPackageManager.Stub {
int i;
for (i=0; i<files.length; i++) {
File file = new File(dir, files[i]);
- if (files[i] != null && files[i].endsWith(".zip")) {
- // Public resource for forward locked package. Ignore
+ if (!isPackageFilename(files[i])) {
+ // Ignore entries which are not apk's
continue;
}
PackageParser.Package pkg = scanPackageLI(file,
@@ -2936,11 +2891,6 @@ class PackageManagerService extends IPackageManager.Stub {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
}
- // We don't expect installation to fail beyond this point,
- if ((scanMode&SCAN_MONITOR) != 0) {
- mAppDirs.put(pkg.mPath, pkg);
- }
-
// Request the ActivityManager to kill the process(only for existing packages)
// so that we do not end up in a confused state while the user is still using the older
// version of the application while the new one gets installed.
@@ -2950,6 +2900,10 @@ class PackageManagerService extends IPackageManager.Stub {
}
synchronized (mPackages) {
+ // We don't expect installation to fail beyond this point,
+ if ((scanMode&SCAN_MONITOR) != 0) {
+ mAppDirs.put(pkg.mPath, pkg);
+ }
// Add the new setting to mSettings
mSettings.insertPackageSettingLP(pkgSetting, pkg);
// Add the new setting to mPackages
@@ -4224,19 +4178,24 @@ class PackageManagerService extends IPackageManager.Stub {
return;
}
+ // Ignore packages that are being installed or
+ // have just been installed.
+ if (ignoreCodePath(fullPathStr)) {
+ return;
+ }
+ PackageParser.Package p = null;
+ synchronized (mPackages) {
+ p = mAppDirs.get(fullPathStr);
+ }
if ((event&REMOVE_EVENTS) != 0) {
- synchronized (mInstallLock) {
- PackageParser.Package p = mAppDirs.get(fullPathStr);
- if (p != null) {
- removePackageLI(p, true);
- removedPackage = p.applicationInfo.packageName;
- removedUid = p.applicationInfo.uid;
- }
+ if (p != null) {
+ removePackageLI(p, true);
+ removedPackage = p.applicationInfo.packageName;
+ removedUid = p.applicationInfo.uid;
}
}
if ((event&ADD_EVENTS) != 0) {
- PackageParser.Package p = mAppDirs.get(fullPathStr);
if (p == null) {
p = scanPackageLI(fullPath,
(mIsRom ? PackageParser.PARSE_IS_SYSTEM : 0) |
@@ -4312,13 +4271,6 @@ class PackageManagerService extends IPackageManager.Stub {
}
args.doPostInstall(res.returnCode);
}
- if (args.observer != null) {
- try {
- args.observer.packageInstalled(res.name, res.returnCode);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
- }
- }
// There appears to be a subtle deadlock condition if the sendPackageBroadcast
// call appears in the synchronized block above.
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
@@ -4345,15 +4297,29 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
Runtime.getRuntime().gc();
+ if (args.observer != null) {
+ try {
+ args.observer.packageInstalled(res.name, res.returnCode);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Observer no longer exists.");
+ }
+ }
}
});
}
- static final class InstallParams {
+ interface HandlerParams {
+ void handleStartCopy(IMediaContainerService imcs);
+ void handleServiceError();
+ }
+
+ class InstallParams implements HandlerParams {
final IPackageInstallObserver observer;
int flags;
final Uri packageURI;
final String installerPackageName;
+ private InstallArgs mArgs;
+ private int mRet;
InstallParams(Uri packageURI,
IPackageInstallObserver observer, int flags,
String installerPackageName) {
@@ -4363,13 +4329,118 @@ class PackageManagerService extends IPackageManager.Stub {
this.installerPackageName = installerPackageName;
}
- public int getInstallLocation(IMediaContainerService imcs) {
+ private int getInstallLocation(IMediaContainerService imcs) {
try {
return imcs.getRecommendedInstallLocation(packageURI);
} catch (RemoteException e) {
}
return -1;
}
+
+ public void handleStartCopy(IMediaContainerService imcs) {
+ int ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ if (imcs != null) {
+ // Remote call to find out default install location
+ int loc = getInstallLocation(imcs);
+ // Use install location to create InstallArgs and temporary
+ // install location
+ if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE){
+ ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
+ ret = PackageManager.INSTALL_FAILED_INVALID_APK;
+ } else {
+ if ((flags & PackageManager.INSTALL_EXTERNAL) == 0){
+ if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
+ // Set the flag to install on external media.
+ flags |= PackageManager.INSTALL_EXTERNAL;
+ } else {
+ // Make sure the flag for installing on external
+ // media is unset
+ flags &= ~PackageManager.INSTALL_EXTERNAL;
+ }
+ }
+ // Disable forward locked apps on sdcard.
+ if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0 &&
+ (flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ // Make sure forward locked apps can only be installed
+ // on internal storage
+ Log.w(TAG, "Cannot install protected apps on sdcard");
+ ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+ } else {
+ ret = PackageManager.INSTALL_SUCCEEDED;
+ }
+ }
+ }
+ // Create the file args now.
+ mArgs = createInstallArgs(this);
+ if (ret == PackageManager.INSTALL_SUCCEEDED) {
+ // Create copy only if we are not in an erroneous state.
+ // Remote call to initiate copy using temporary file
+ ret = mArgs.copyApk(imcs, true);
+ }
+ mRet = ret;
+ mHandler.sendEmptyMessage(MCS_UNBIND);
+ handleReturnCode();
+ }
+
+ void handleReturnCode() {
+ processPendingInstall(mArgs, mRet);
+ }
+
+ public void handleServiceError() {
+ mArgs = createInstallArgs(this);
+ mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ handleReturnCode();
+ }
+ };
+
+ /*
+ * Utility class used in movePackage api.
+ * srcArgs and targetArgs are not set for invalid flags and make
+ * sure to do null checks when invoking methods on them.
+ * We probably want to return ErrorPrams for both failed installs
+ * and moves.
+ */
+ class MoveParams implements HandlerParams {
+ final IPackageMoveObserver observer;
+ final int flags;
+ final String packageName;
+ final InstallArgs srcArgs;
+ final InstallArgs targetArgs;
+ int mRet;
+ MoveParams(InstallArgs srcArgs,
+ IPackageMoveObserver observer,
+ int flags, String packageName) {
+ this.srcArgs = srcArgs;
+ this.observer = observer;
+ this.flags = flags;
+ this.packageName = packageName;
+ if (srcArgs != null) {
+ Uri packageUri = Uri.fromFile(new File(srcArgs.getCodePath()));
+ targetArgs = createInstallArgs(packageUri, flags, packageName);
+ } else {
+ targetArgs = null;
+ }
+ }
+
+ public void handleStartCopy(IMediaContainerService imcs) {
+ // Create the file args now.
+ mRet = targetArgs.copyApk(imcs, false);
+ targetArgs.doPreInstall(mRet);
+ mHandler.sendEmptyMessage(MCS_UNBIND);
+ handleReturnCode();
+ }
+
+ void handleReturnCode() {
+ targetArgs.doPostInstall(mRet);
+ // TODO invoke pending move
+ processPendingMove(this, mRet);
+ }
+
+ public void handleServiceError() {
+ mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ handleReturnCode();
+ }
};
private InstallArgs createInstallArgs(InstallParams params) {
@@ -4388,8 +4459,18 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ private InstallArgs createInstallArgs(Uri packageURI, int flags, String pkgName) {
+ if (installOnSd(flags)) {
+ String cid = getNextCodePath(null, pkgName, "/" + SdInstallArgs.RES_FILE_NAME);
+ return new SdInstallArgs(packageURI, cid);
+ } else {
+ return new FileInstallArgs(packageURI, pkgName);
+ }
+ }
+
static abstract class InstallArgs {
final IPackageInstallObserver observer;
+ // Always refers to PackageManager flags only
final int flags;
final Uri packageURI;
final String installerPackageName;
@@ -4404,7 +4485,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
abstract void createCopyFile();
- abstract int copyApk(IMediaContainerService imcs);
+ abstract int copyApk(IMediaContainerService imcs, boolean temp);
abstract int doPreInstall(int status);
abstract boolean doRename(int status, String pkgName, String oldCodePath);
abstract int doPostInstall(int status);
@@ -4419,6 +4500,7 @@ class PackageManagerService extends IPackageManager.Stub {
File installDir;
String codeFileName;
String resourceFileName;
+ boolean created = false;
FileInstallArgs(InstallParams params) {
super(params.packageURI, params.observer,
@@ -4433,6 +4515,15 @@ class PackageManagerService extends IPackageManager.Stub {
resourceFileName = fullResourcePath;
}
+ FileInstallArgs(Uri packageURI, String pkgName) {
+ super(packageURI, null, 0, null);
+ boolean fwdLocked = isFwdLocked(flags);
+ installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir;
+ String apkName = getNextCodePath(null, pkgName, ".apk");
+ codeFileName = new File(installDir, apkName + ".apk").getPath();
+ resourceFileName = getResourcePathFromCodePath();
+ }
+
String getCodePath() {
return codeFileName;
}
@@ -4442,11 +4533,29 @@ class PackageManagerService extends IPackageManager.Stub {
installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir;
codeFileName = createTempPackageFile(installDir).getPath();
resourceFileName = getResourcePathFromCodePath();
+ created = true;
}
- int copyApk(IMediaContainerService imcs) {
+ int copyApk(IMediaContainerService imcs, boolean temp) {
+ if (temp) {
+ // Generate temp file name
+ createCopyFile();
+ }
// Get a ParcelFileDescriptor to write to the output file
File codeFile = new File(codeFileName);
+ if (!created) {
+ try {
+ codeFile.createNewFile();
+ // Set permissions
+ if (!setPermissions()) {
+ // Failed setting permissions.
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to create file " + codeFile);
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ }
+ }
ParcelFileDescriptor out = null;
try {
out = ParcelFileDescriptor.open(codeFile,
@@ -4491,7 +4600,7 @@ class PackageManagerService extends IPackageManager.Stub {
codeFileName = desFile.getPath();
resourceFileName = getResourcePathFromCodePath();
// Set permissions
- if (!setPermissions(pkgName)) {
+ if (!setPermissions()) {
// Failed setting permissions.
return false;
}
@@ -4558,7 +4667,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- private boolean setPermissions(String pkgName) {
+ private boolean setPermissions() {
// TODO Do this in a more elegant way later on. for now just a hack
if (!isFwdLocked(flags)) {
final int filePermissions =
@@ -4594,7 +4703,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
SdInstallArgs(String fullCodePath, String fullResourcePath) {
- super(null, null, ApplicationInfo.FLAG_ON_SDCARD, null);
+ super(null, null, PackageManager.INSTALL_EXTERNAL, null);
// Extract cid from fullCodePath
int eidx = fullCodePath.lastIndexOf("/");
String subStr1 = fullCodePath.substring(0, eidx);
@@ -4604,7 +4713,12 @@ class PackageManagerService extends IPackageManager.Stub {
}
SdInstallArgs(String cid) {
- super(null, null, ApplicationInfo.FLAG_ON_SDCARD, null);
+ super(null, null, PackageManager.INSTALL_EXTERNAL, null);
+ this.cid = cid;
+ }
+
+ SdInstallArgs(Uri packageURI, String cid) {
+ super(packageURI, null, PackageManager.INSTALL_EXTERNAL, null);
this.cid = cid;
}
@@ -4612,7 +4726,10 @@ class PackageManagerService extends IPackageManager.Stub {
cid = getTempContainerId();
}
- int copyApk(IMediaContainerService imcs) {
+ int copyApk(IMediaContainerService imcs, boolean temp) {
+ if (temp) {
+ createCopyFile();
+ }
try {
cachePath = imcs.copyResourceToContainer(
packageURI, cid,
@@ -4771,8 +4888,8 @@ class PackageManagerService extends IPackageManager.Stub {
if (sidx != -1) {
subStr = subStr.substring(sidx + prefix.length());
if (subStr != null) {
- if (subStr.startsWith("-")) {
- subStr = subStr.substring(1);
+ if (subStr.startsWith(INSTALL_PACKAGE_SUFFIX)) {
+ subStr = subStr.substring(INSTALL_PACKAGE_SUFFIX.length());
}
try {
idx = Integer.parseInt(subStr);
@@ -4786,10 +4903,26 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
- idxStr = "-" + Integer.toString(idx);
+ idxStr = INSTALL_PACKAGE_SUFFIX + Integer.toString(idx);
return prefix + idxStr;
}
+ // Utility method used to ignore ADD/REMOVE events
+ // by directory observer.
+ private static boolean ignoreCodePath(String fullPathStr) {
+ String apkName = getApkName(fullPathStr);
+ int idx = apkName.lastIndexOf(INSTALL_PACKAGE_SUFFIX);
+ if (idx != -1 && ((idx+1) < apkName.length())) {
+ // Make sure the package ends with a numeral
+ String version = apkName.substring(idx+1);
+ try {
+ Integer.parseInt(version);
+ return true;
+ } catch (NumberFormatException e) {}
+ }
+ return false;
+ }
+
// Utility method that returns the relative package path with respect
// to the installation directory. Like say for /data/data/com.test-1.apk
// string com.test-1 is returned.
@@ -5055,6 +5188,19 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ // Utility method used to move dex files during install.
+ private int moveDexFiles(PackageParser.Package newPackage) {
+ int retCode;
+ if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath);
+ if (retCode != 0) {
+ Log.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ }
+ }
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
private void updateSettingsLI(PackageParser.Package newPackage,
String installerPackageName, PackageInstalledInfo res) {
String pkgName = newPackage.packageName;
@@ -5066,27 +5212,20 @@ class PackageManagerService extends IPackageManager.Stub {
mSettings.writeLP();
}
- int retCode = 0;
- if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
- retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath);
- if (retCode != 0) {
- Log.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
- res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- return;
- }
- }
- res.returnCode = setPermissionsLI(newPackage);
- if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ if ((res.returnCode = moveDexFiles(newPackage))
+ != PackageManager.INSTALL_SUCCEEDED) {
+ // Discontinue if moving dex files failed.
return;
- } else {
- Log.d(TAG, "New package installed in " + newPackage.mPath);
}
- if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ if((res.returnCode = setPermissionsLI(newPackage))
+ != PackageManager.INSTALL_SUCCEEDED) {
if (mInstaller != null) {
mInstaller.rmdex(newPackage.mScanPath);
}
+ return;
+ } else {
+ Log.d(TAG, "New package installed in " + newPackage.mPath);
}
-
synchronized (mPackages) {
grantPermissionsLP(newPackage, true);
res.name = pkgName;
@@ -6765,9 +6904,13 @@ class PackageManagerService extends IPackageManager.Stub {
HashSet<String> loadedPermissions = new HashSet<String>();
GrantedPermissions(int pkgFlags) {
+ setFlags(pkgFlags);
+ }
+
+ void setFlags(int pkgFlags) {
this.pkgFlags = (pkgFlags & ApplicationInfo.FLAG_SYSTEM) |
- (pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) |
- (pkgFlags & ApplicationInfo.FLAG_ON_SDCARD);
+ (pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) |
+ (pkgFlags & ApplicationInfo.FLAG_ON_SDCARD);
}
}
@@ -8662,11 +8805,6 @@ class PackageManagerService extends IPackageManager.Stub {
uidArr[di++] = uidList[i];
}
}
- if (true) {
- for (int j = 0; j < num; j++) {
- Log.i(TAG, "uidArr[" + j + "]=" + uidArr[j]);
- }
- }
}
if (mediaStatus) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
@@ -8779,4 +8917,145 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
+
+ public void movePackage(final String packageName,
+ final IPackageMoveObserver observer, final int flags) {
+ if (packageName == null) {
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MOVE_PACKAGE, null);
+ int returnCode = PackageManager.MOVE_SUCCEEDED;
+ int currFlags = 0;
+ int newFlags = 0;
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
+ }
+ // Disable moving fwd locked apps and system packages
+ if (pkg.applicationInfo != null &&
+ (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ Log.w(TAG, "Cannot move system application");
+ returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+ } else if (pkg.applicationInfo != null &&
+ (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) {
+ Log.w(TAG, "Cannot move forward locked app.");
+ returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED;
+ } else {
+ // Find install location first
+ if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 &&
+ (flags & PackageManager.MOVE_INTERNAL) != 0) {
+ Log.w(TAG, "Ambigous flags specified for move location.");
+ returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
+ } else {
+ newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ?
+ PackageManager.INSTALL_EXTERNAL : 0;
+ currFlags = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0 ?
+ PackageManager.INSTALL_EXTERNAL : 0;
+ if (newFlags == currFlags) {
+ Log.w(TAG, "No move required. Trying to move to same location");
+ returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
+ }
+ }
+ }
+ if (returnCode != PackageManager.MOVE_SUCCEEDED) {
+ processPendingMove(new MoveParams(null, observer, 0, null), returnCode);
+ } else {
+ Message msg = mHandler.obtainMessage(INIT_COPY);
+ InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir,
+ pkg.applicationInfo.publicSourceDir);
+ MoveParams mp = new MoveParams(srcArgs, observer, newFlags,
+ packageName);
+ msg.obj = mp;
+ mHandler.sendMessage(msg);
+ }
+ }
+ }
+
+ private void processPendingMove(final MoveParams mp, final int currentStatus) {
+ // Queue up an async operation since the package deletion may take a little while.
+ mHandler.post(new Runnable() {
+ public void run() {
+ mHandler.removeCallbacks(this);
+ int returnCode = currentStatus;
+ boolean moveSucceeded = (returnCode == PackageManager.MOVE_SUCCEEDED);
+ if (moveSucceeded) {
+ int uid = -1;
+ synchronized (mPackages) {
+ uid = mPackages.get(mp.packageName).applicationInfo.uid;
+ }
+ ArrayList<String> pkgList = new ArrayList<String>();
+ pkgList.add(mp.packageName);
+ int uidArr[] = new int[] { uid };
+ // Send resources unavailable broadcast
+ sendResourcesChangedBroadcast(false, pkgList, uidArr);
+
+ // Update package code and resource paths
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(mp.packageName);
+ if (pkg != null) {
+ String oldCodePath = pkg.mPath;
+ String newCodePath = mp.targetArgs.getCodePath();
+ String newResPath = mp.targetArgs.getResourcePath();
+ pkg.mPath = newCodePath;
+ // Move dex files around
+ if (moveDexFiles(pkg)
+ != PackageManager.INSTALL_SUCCEEDED) {
+ // Moving of dex files failed. Set
+ // error code and abort move.
+ pkg.mPath = pkg.mScanPath;
+ returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ moveSucceeded = false;
+ } else {
+ pkg.mScanPath = newCodePath;
+ pkg.applicationInfo.sourceDir = newCodePath;
+ pkg.applicationInfo.publicSourceDir = newResPath;
+ PackageSetting ps = (PackageSetting) pkg.mExtras;
+ ps.codePath = new File(pkg.applicationInfo.sourceDir);
+ ps.codePathString = ps.codePath.getPath();
+ ps.resourcePath = new File(pkg.applicationInfo.publicSourceDir);
+ ps.resourcePathString = ps.resourcePath.getPath();
+ // Set the application info flag correctly.
+ if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_ON_SDCARD;
+ } else {
+ pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_ON_SDCARD;
+ }
+ ps.setFlags(pkg.applicationInfo.flags);
+ mAppDirs.remove(oldCodePath);
+ mAppDirs.put(newCodePath, pkg);
+ // Persist settings
+ mSettings.writeLP();
+ }
+ }
+ }
+ if (moveSucceeded) {
+ // Delete older code
+ synchronized (mInstallLock) {
+ mp.srcArgs.cleanUpResourcesLI();
+ }
+ // Send resources available broadcast
+ sendResourcesChangedBroadcast(true, pkgList, uidArr);
+ Runtime.getRuntime().gc();
+ }
+ }
+ if (!moveSucceeded){
+ // Clean up failed installation
+ if (mp.targetArgs != null) {
+ mp.targetArgs.doPostInstall(
+ PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
+ }
+ }
+ IPackageMoveObserver observer = mp.observer;
+ if (observer != null) {
+ try {
+ observer.packageMoved(mp.packageName, returnCode);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Observer no longer exists.");
+ }
+ }
+ }
+ });
+ }
}