基於android5.1的源碼進行分析,源碼是上游廠商提供,所以和google源生的代碼會有一些差異.
下面先來點系統掃描的堆棧:
java.lang.Throwable
at com.android.server.pm.PackageManagerService.<init>(PackageManagerService.java:1325)
at com.android.server.pm.PackageManagerService.main(PackageManagerService.java:1287)
at com.android.server.SystemServer.startBootstrapServices(SystemServer.java:376)
at com.android.server.SystemServer.run(SystemServer.java:275)
at com.android.server.SystemServer.main(SystemServer.java:191)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:947)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:742)
我們先來看看下面都有一些什麼東西值得我們去留意的
private void run() {
.............
/*設置當前時間,如果當前時間不是EARLIEST_SUPPORTED_TIME之後的,則把當前時間設置成EARLIEST_SUPPORTED_TIME的*/
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
..........
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Start services.
try {
startBootstrapServices(); //這個是我們重點關注的地方,後面將圍繞這個來展開
startCoreServices();
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
......................
}
現在我們來重點關注: startBootstrapServices()裏面最主要的內容仍然是PackageManagerService(),下面,我們來看下 PackageManagerService()這個裏面到底有什麼東西.我是因爲重啓機器後launcher3的桌面widget會被刪除纔來分析這個地方的,所以關注的點就在這裏,所以有一些地方可能沒有關注到,所以 爲看官到時候可以在評論裏給出一些建議.
好,下面我們正式對這個部分的重點進行分析(注:我們只是對關鍵的地方進行分析和說明,一些和解決問題不你的地方可能會被過濾掉):
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
...
//獲取當前的模式,盤對是不能在是模式當中
String mode = SystemProperties.get("ro.bootmode", "mode");
//獲取當前的開機方式,power鍵+上下鍵方式和正常開機方式所進入的界面是不一樣的
mFactoryTest = factoryTest;
engModeEnable = "engtest".equals(mode) ? true : false;
...
//獲得當前 不 debug版本的狀態,debugh和 user版本的狀態是完全不一樣的
mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
// TODO: add a property to control this?
//創建SharedUserSetting對象並添加到Settings的成員變量mSharedUsers中,在Android系統中,多個package通過設置sharedUserId屬性可以運行在同一個進程,共享同一個UID*
mSettings = new Settings(context);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
long dexOptLRUThresholdInMinutes;
if (mLazyDexOpt) {
dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
} else {
dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
}
mDexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;
//
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
if ("*".equals(separateProcesses)) {
mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
mSeparateProcesses = null;
Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
} else {
mDefParseFlags = 0;
mSeparateProcesses = separateProcesses.split(",");
Slog.w(TAG, "Running with debug.separate_processes: "
+ separateProcesses);
}
} else {
mDefParseFlags = 0;
mSeparateProcesses = null;
}
...
mInstaller = installer; //創建應用安裝器
...
//下面段代碼,我們知道,主要是掃描app-private這個目錄的,掃描更新service裏面的信息,在launcher3中掃描安裝widget的時候,對比包中就是使用這裏的信息進行對比 ,這個掃描更新的信息沒有存入到package數據庫裏面的話,widget將會刪除信息相應的widget.widget對比中之所以會被刪除,是因爲launcher的啓動速度比掃描服務來得更早和更快,所以造成package數據庫裏面有沒有相應的包信息.
final File drmInstallDir = new File("/data/app-private/");
new Thread("drmapp"){
@Override
public void run() {
long startTime = SystemClock.uptimeMillis();
scanDirLI(drmInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanFlags, 0);
mConnectedSignal2.countDown();
}
}.start();
//waitForLatch相當與一個延時的語句,延時等待掃描的完成
waitForLatch(mConnectedSignal2);
}
//下面這個函數定義就是掃描目錄的一個具體的實現方式,在這個過程中,我們可以看到目錄的增加和刪除都在這裏面進行,這個函數的//作用我們能看得出來,這裏調用了一個關鍵的方法對掃描行爲做更進一步的處理. scanPackageLI
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
return;
}
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
+ " flags=0x" + Integer.toHexString(parseFlags));
}
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
try {
scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
// Delete invalid userdata apps
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
if (file.isDirectory()) {
FileUtils.deleteContents(file);
}
file.delete();
}
}
}
}
/*===========================================================*/
/* @} */
/*
* Scan a package and return the newly parsed package.
* Returns null in case of errors and the error code is stored in mLastScanError
*/
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,long currentTime, UserHandle user) throws PackageManagerException {
...
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(scanFile, parseFlags); //獲取pack的info信息
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
if(isPreloadOrVitalApp(scanFile.getParent()) && mDeleteRecord.exists()){
if(isDeleteApp(pkg.packageName))return pkg;
}
...
synchronized (mPackages) {
...
String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
ps = mSettings.peekPackageLPr(oldName);
}
if (ps == null) {
ps = mSettings.peekPackageLPr(pkg.packageName);
}
// Check to see if this package could be hiding/updating a system
// package. Must look for it either under the original or real
// package name depending on our state.
updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
}
boolean updatedPkgBetter = false;
// First check if this is a system package that may involve an update
if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
// If new package is not located in "/system/priv-app" (e.g. due to an OTA),
// it needs to drop FLAG_PRIVILEGED.
...
if (ps != null && !ps.codePath.equals(scanFile)) {
// The path has changed from what was last scanned... check the
// version of the new path against what we have stored to determine
// what to do.
if (pkg.mVersionCode <= ps.versionCode) {
...
updatedPkg.codePath = scanFile;
updatedPkg.codePathString = scanFile.toString();
}
updatedPkg.pkg = pkg;
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null);
} else {
// The current app on the system partition is better than
// what we have updated to on the data partition; switch
// back to the system partition version.
// At this point, its safely assumed that package installation for
// apps in system partition will go through. If not there won't be a working
// version of the app
// writer
synchronized (mPackages) {
// Just remove the loaded entries from package lists.
mPackages.remove(ps.name);
}
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
getAppDexInstructionSets(ps));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
synchronized (mPackages) {
mSettings.enableSystemPackageLPw(ps.name);
}
updatedPkgBetter = true;
}
}
}
...
// Verify certificates against what was last scanned
collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);
/*
* A new system app appeared, but we already had a non-system one of the
* same name installed earlier.
*/
boolean shouldHideSystemApp = false;
if (updatedPkg == null && ps != null
&& (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
/*
* Check to make sure the signatures match first. If they don't,
* wipe the installed application and its data.
*/
if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false);
ps = null;
} else {
/*
* If the newly-added system app is an older version than the
* already installed version, hide it. It will be scanned later
* and re-added like an update.
*/
if (pkg.mVersionCode <= ps.versionCode) {
shouldHideSystemApp = true;
} else {
/*
* The newly found system app is a newer version that the
* one previously installed. Simply remove the
* already-installed application and replace it with our own
* already-installed application and replace it with our own
* while keeping the application data.
*/
...
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,getAppDexInstructionSets(ps));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
}
}
}