该流程主要是在PackageManagerService.java中
首先通过内部类AppDirObserver extends FileObserver监听没一个应用创建的文件夹,在插拔SD卡时的onEvent中调用
p = scanPackageLI(fullPath, flags,
SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
System.currentTimeMillis(), UserHandle.ALL);
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime, UserHandle user) {
.......
// 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.
if ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
// If the package lives in an asec, tell everyone that the container is going
// away so they can clean up any references to its resources (which would prevent
// vold from being able to unmount the asec)
if (isForwardLocked(pkg) || isExternal(pkg)) {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + pkg + " is ASEC-hosted -> UNAVAILABLE");
}
final int[] uidArray = new int[] { pkg.applicationInfo.uid };
final ArrayList<String> pkgList = new ArrayList<String>(1);
pkgList.add(pkg.applicationInfo.packageName);
sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
}
// Post the request that it be killed now that the going-away broadcast is en route
killApplication(pkg.applicationInfo.packageName,
pkg.applicationInfo.uid, "update pkg");
}
.........
}
private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
int size = pkgList.size();
if (size > 0) {
// Send broadcasts here
Bundle extras = new Bundle();
extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList
.toArray(new String[size]));
if (uidArr != null) {
extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
}
if (replacing && !mediaStatus) {
extras.putBoolean(Intent.EXTRA_REPLACING, replacing);
}
String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
: Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
sendPackageBroadcast(action, null, extras, null, finishedReceiver, null);
}
}
然后发出Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE在LauncherModel.java有接受该Intent
/**
* Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and
* ACTION_PACKAGE_CHANGED.
*/
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);
final String action = intent.getAction();
if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
|| Intent.ACTION_PACKAGE_REMOVED.equals(action)
|| Intent.ACTION_PACKAGE_ADDED.equals(action)) {
......
}else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
if (!replacing) {
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
enqueuePackageUpdated(new PackageUpdatedTask(
PackageUpdatedTask.OP_UNAVAILABLE, packages));
}
// else, we are replacing the packages, so ignore this event and wait for
// EXTERNAL_APPLICATIONS_AVAILABLE to update the packages at that time
}
......
}
启动PackageUpdatedTask线程
执行
private class PackageUpdatedTask implements Runnable {
........
if (packageRemoved) {
for (String pn : removedPackageNames) {
ArrayList<ItemInfo> infos = getItemInfoForPackageName(pn);
for (ItemInfo i : infos) {
deleteItemFromDatabase(context, i);
}
}
// Remove any queued items from the install queue
String spKey = LauncherAppState.getSharedPreferencesKey();
SharedPreferences sp =
context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
InstallShortcutReceiver.removeFromInstallQueue(sp, removedPackageNames)
........
}
static void deleteItemFromDatabase(Context context, final ItemInfo item) {
........
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
sBgWorkspaceItems.remove(item);
break;
........
sBgItemsIdMap.remove(item.id);
sBgDbIconCache.remove(item);
........
}