Android 開機過程PMS分析


 

 

 

 

12-13 12:25:05.595  3253  3253 SystemServer !@Boot: Start PackageManagerService

pm/PackageManagerService.java
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore)
PMS的構造函數中
① mSettings 初始化,發現 packages.list 找不到 報出以上的log
mSettings = new Settings(context);
//因為data分區 被Security的加密feature卸載,所以data下面的文件全都找不到
12-13 12:25:05.625  3253  3253 SELinuxMMAC Error opening /data/system/seapp_hash. Assuming first boot.
12-13 12:25:05.640  3253  3253 FileUtils Failed to chmod(/data/system/packages.list): android.system.ErrnoException: chmod failed: ENOENT (No such file or directory)

②  SystemConfig systemConfig = SystemConfig.getInstance();
    mGlobalGids = systemConfig.getGlobalGids();
    mSystemPermissions = systemConfig.getSystemPermissions();
    mAvailableFeatures = systemConfig.getAvailableFeatures();
    packages.xml在data目錄下,所以也找不到

12-13 12:25:05.650  3253  3253 SystemConfig No directory /system/etc/sysconfig, skipping
12-13 12:25:05.940  3253  3253 SystemConfig Got execption parsing permissions.
org.xmlpull.v1.XmlPullParserException: No start tag found
    at com.android.server.SystemConfig.readPermissionsFromXml(SystemConfig.java:193)
    at com.android.server.SystemConfig.readPermissions(SystemConfig.java:164)
    at com.android.server.SystemConfig.<init>(SystemConfig.java:126)
    at com.android.server.SystemConfig.getInstance(SystemConfig.java:87)
    at com.android.server.pm.PackageManagerService.<init>(PackageManagerService.java:1937)
    at com.android.server.pm.PackageManagerService.main(PackageManagerService.java:1825)
    at com.android.server.SystemServer.startBootstrapServices(SystemServer.java:514)
    at com.android.server.SystemServer.run(SystemServer.java:412)
    at com.android.server.SystemServer.main(SystemServer.java:313)
    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:1389)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1184)
12-13 12:25:06.060  3253  3253 Revision File not found at: /data/security/sepolicy
12-13 12:25:06.060  3253  3253 Revision File not found at: /data/security/spota/sepolicy_version
12-13 12:25:06.065  3253  3253 xxxxxxsetupresourcelist entered setup resource list in selinuxmmac
12-13 12:25:06.065  3253  3253 SELinuxMMAC Read and parse file: /system/etc/security/mac_permissions.xml
12-13 12:25:06.665  3253  3253 SELinuxMMAC Read and parse file: /data/security/good/mac_permissions.xml
12-13 12:25:06.665  3253  3253 SELinuxMMAC File not found exception: /data/security/good/mac_permissions.xml
12-13 12:25:06.665  3253  3253 SELinuxMMAC Read and parse file: /data/security/mycontainer/mac_permissions.xml
12-13 12:25:06.665  3253  3253 SELinuxMMAC File not found exception: /data/security/mycontainer/mac_permissions.xml
12-13 12:25:06.665  3253  3253 SELinuxMMAC Read and parse file: /data/security/whitelist/mac_permissions.xml
12-13 12:25:06.665  3253  3253 SELinuxMMAC File not found exception: /data/security/whitelist/mac_permissions.xml

    mInstaller = installer;
    mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
    // Process.THREAD_PRIORITY_BACKGROUND) 設置線程優先級為后台,這樣當多個線程並發后很多無關緊要的線程分配的CPU時間將會減少,有利於主線程的處理
    mHandlerThread.start();
    mHandler = new PackageHandler(mHandlerThread.getLooper()); 用一個后台線程來處理安裝請求
    Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);

    File dataDir = Environment.getDataDirectory();
    mAppDataDir = new File(dataDir, "data");
    mAppInstallDir = new File(dataDir, "app");
    mAppLib32InstallDir = new File(dataDir, "app-lib");
    mAsecInternalPath = new File(dataDir, "app-asec").getPath();
    mUserAppDataDir = new File(dataDir, "user");
    mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

     ArrayMap<String, SystemConfig.PermissionEntry> permConfig = systemConfig.getPermissions(); //權限管理配置相關
     ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries(); //共享庫配置 相關
     

③  mFoundPolicyFile = SELinuxMMAC.readInstallPolicy(); //scan SELinux install policy耗時
    mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false), mSdkVersion, mOnlyCore); //pm/Settings.java
    readLPw的時候發現data目錄下的 packages.xml 找不到了,重建一個,同時return false
    mRestoredSettings =false, 則被認為是第一次燒機,或者重置。 所以:First Boot Or Factory Reset : I9502ZNUHNL2

12-13 12:25:06.670  3253  3253 PackageManager Time to scan SELinux install policy: 0.612 seconds
12-13 12:25:06.670  3253  3253 PackageManager No settings file; creating initial state
12-13 12:25:06.675  3253  3253 PackageManager First Boot Or Factory Reset : I9502ZNUHNL2

    String customResolverActivity = Resources.getSystem().getString( R.string.config_customResolverActivity);
    if (TextUtils.isEmpty(customResolverActivity)) {
        customResolverActivity = null;
    } else {
        mCustomResolverComponentName = ComponentName.unflattenFromString(customResolverActivity);
    }
    使用客戶化的 customResolverActivity 來替代系統原有的,如果沒有客戶化的,就調用系統原有的
    
    "/data/system/.aasa/managedpackages.xml";
    AASA_readXml();
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime); //系統掃描開始,打出掃描開始時間
    
    final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING; //設定掃描的flag
    final HashSet<String> alreadyDexOpted = new HashSet<String>(); //保存 DexOpted已經解析過的
    
    zygote 啟動的時候,如果必要的話,會運行dexopt。所以要將 boot class path 中的所有東西 都添加上
    final String bootClassPath = System.getenv("BOOTCLASSPATH"); //Libcore.os.getenv(name);
    final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
    在bootClassPath和systemServerClassPath 下的 默認 加入alreadyDexOpted。
    
④    boolean didDexOptLibraryOrTool = false; //初始化,沒有運行過dexopt的庫或工具
    final List<String> allInstructionSets = getAllInstructionSets(); //取得所有指令集
    final String[] dexCodeInstructionSets = getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()])); //所有指令集中,dexCode相關的指令集
    if (mSharedLibraries.size() > 0) {...} //確保所有的external libraries 有dexopt運行過。
    找到這個lib以后,將它加入alreadyDexOpted,並且調用  mInstaller.dexopt或mInstaller.patchoat 解析成可用的東西。 didDexOptLibraryOrTool = true;
    // NOTE: For now, we're compiling these system "shared libraries"
    // (and framework jars) into all available architectures. It's possible
    // to compile them only when we come across an app that uses them (there's
    // already logic for that in scanPackageLI) but that adds some complexity.
    對象: "shared libraries" (and framework jars)
    
12-13 12:25:07.795  3253  3253 PackageManager Library not found: /system/framework/javax.btobex.jar
12-13 12:25:08.755  3253  3253 PackageManager Library not found: /system/framework/imsmanager-internal.jar

    File frameworkDir = new File(Environment.getRootDirectory(), "framework"); // 對system/framework目錄下的東西進行處理
    framework-res.apk, twframework-res.apk, 不解析,因為不包含任何代碼
    core-libart.jar , boot class path路徑下的,art使用的東西,已經處理過了,不處理了
    String[] frameworkFiles = frameworkDir.list(); //在java中實現了許多命令,需要dexopt來解析
    只處理 .apk 和 .jar 類型的文件, 如果有需要解析的 也會把 didDexOptLibraryOrTool設為true.

⑤ if (didDexOptLibraryOrTool || "1".equals(SystemProperties.get("sys.prune_dex_cache", "unknown"))) {...}
   //If we dexopted a library or tool, then something on the system has changed.
   這部分本應該在boot classpath中做,但是由於 DexFile.isDexOptNeeded 對所有的boot classpath文件返回為false,所以我們要在這里做。
   這部分是耗時最長的

12-13 12:25:12.480  3253  3253 PackageManager System has been changed!! : I9502ZNUHNL2

⑥    File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
    final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
    vendorOverlayDir = "/vendor/overlay"
    frameworkDir = "/system/framework"
    privilegedAppDir = "/system/priv-app"
    carrierAppDir = "/carrier/itson/app"
    systemAppDir = "/system/app"
    vendorAppDir = "/vendor/app"
    oemAppDir = 
    containerAppDir = "/system/container"
    掃描以上目錄中存在的 packages, 然后交給scanDirLI()處理, scanDirLI() 具體做了哪些操作待定
12-13 12:25:12.505  3253  3253 PackageManager not yet prefetched, retry parse package: 
12-13 12:25:21.315  3253  3253 PackageManager Permission android.permission.sec.MDM_ENTERPRISE_VPN_SOLUTION from package android ignored: no group null
......
12-13 12:25:24.200  3253  3253 PackageManager not yet prefetched, retry parse package: 
12-13 12:25:24.205  3253  3253 PackageManager Failed to parse /system/priv-app/LogsProvider: Not a coreApp: /system/priv-app/LogsProvider
......
12-13 12:25:48.435  3253  3253 PackageManager not yet prefetched, retry parse package:
12-13 12:25:48.435  3253  3253 PackageManager Failed to parse /system/container/resources: Missing base APK in /system/container/resources

Line 3774: 12-13 12:25:12.480  3566  3566 dex2oat dex2oat took 35.592ms (threads: 4)
Line 3970: 12-13 12:25:48.490  3573  3573 dex2oat dex2oat took 23.313ms (threads: 4) //這個時間段沒有跑dex2oat, 所以需要仔細分析.

scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags | SCAN_NO_DEX, 0);
scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
scanDirLI(carrierAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0); //CSC控制
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
scanDirLI(containerAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);




    if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
    mInstaller.moveFiles();

    修減 packages.xml 中保存的不再存在的 system packages。// Prune any system packages that no longer exist.
    mOnlyCore = onlyCore; // 參數傳入的。
    if (!mOnlyCore) {
        Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
        while (psit.hasNext()) {
            PackageSetting ps = psit.next();
    !ApplicationInfo.FLAG_SYSTEM: 不是系統apk,略
    if (mSettings.isDisabledSystemPackageLPr(ps.name)){
        removePackageLI(ps, true);
        expectingBetter.put(ps.name, ps.codePath);
        如果有 FLAG_SYSTEM, 並且在 disabled packages list 中,那么這個apk一定是通過OTA添加的。
        將它從當前掃描中移除,然后先前user-installed的應用就會被掃描到。
        加入到 expectingBetter 中。
    }
    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
        psit.remove();
        removeDataDirsLI(ps.name);
        //added to remove package setting's deleted package information
        int ret = mSettings.removePackageLPw(ps);
        如果有 FLAG_SYSTEM, 並且 不是disabled的系統apk,  從mSettings中移除.
    } else {
        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
        if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
            possiblyDeletedUpdatedSystemApps.add(ps.name);
        }
        mSettings中已經標識的 disabled 的系統apk, 放到 possiblyDeletedUpdatedSystemApps 中。
    }
    
    
    //look for any incomplete package installations. 查找所有安裝 不完全 的package
    cleanupInstallFailedPackage(deletePkgsList.get(i));    //清除掉安裝失敗的 package
    deleteTempPackageFiles();    //刪除臨時文件
    mSettings.pruneSharedUsersLPw();    //移除掉所有 和 shared userIDs 無關的 packages
    
    
    if (!mOnlyCore) {
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); //開始掃描data目錄
        scanDirLI(mAppInstallDir, 0, scanFlags, 0);    //掃描app安裝目錄 data/app
        scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanFlags, 0);    //特權apk安裝目錄 data/app-private
        
        Remove disable package settings for any updated system apps that were removed via an OTA. If they're not a previously-updated app, remove them completely.
        Otherwise, just revoke their system-level permissions.
        
        for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
            PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
            mSettings.removeDisabledSystemPackageLPw(deletedAppName);   //mSettings中移除 disable掉的 系統apk
            if (deletedPkg == null) {  //被更新的系統apk已經不再存在。
                removeDataDirsLI(deletedAppName);    // 擦出它的數據目錄,
                PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                int ret = mSettings.removePackageLPw(deletedPs);    // 移除掉mSetting中的該apk的信息
            } else {    //被更新的系統apk已經不再出現,移除它的系統特權
                deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
                PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
            }// end if-else
        }// end for
    }// end if (!mOnlyCore)
    
    
     /**
      * Make sure all system apps that we expected to appear on
      * the userdata partition actually showed up. If they never
      * appeared, crawl back and revive the system version.
      */確保所有的我們期望顯示的apk都被顯示出來了。如果它們從來沒有顯示過,將他們回復到系統版本
    for (int i = 0; i < expectingBetter.size(); i++) {
        final String packageName = expectingBetter.keyAt(i);
        if (!mPackages.containsKey(packageName)) {
            privilegedAppDir, systemAppDir, vendorAppDir, oemAppDir,
            mSettings.enableSystemPackageLPw(packageName);
            scanPackageLI(scanFile, reparseFlags, scanFlags, 0, null);
        }
    } //end for
// Now that we know all of the shared libraries, update all clients to have the correct library paths.
    updateAllSharedLibrariesLPw();    //我們知道了所有的共享庫路徑,更新所有的客戶 使用正確的library paths.
12-13 12:25:48.440  3253  3253 PackageManager Package com.android.server.telecom desires unavailable shared library commonimsinterface; ignoring!
12-13 12:25:48.440  3253  3253 PackageManager Package com.android.settings desires unavailable shared library com.google.android.maps; ignoring!
12-13 12:25:48.440  3253  3253 PackageManager Package com.android.settings desires unavailable shared library TmoWfcUtils; ignoring!
12-13 12:25:48.440  3253  3253 PackageManager Package com.android.settings desires unavailable shared library commonimsinterface; ignoring!
12-13 12:25:48.440  3253  3253 PackageManager Package com.android.systemui desires unavailable shared library TmoWfcUtils; ignoring!
12-13 12:25:48.440  3253  3253 PackageManager Package com.android.phone desires unavailable shared library commonimsinterface; ignoring!
12-13 12:25:48.440  3253  3253 PackageManager Package com.android.phone desires unavailable shared library TmoWfcUtils; ignoring!
12-13 12:25:48.440  3253  3253 PackageManager Package com.android.incallui desires unavailable shared library commonimsinterface; ignoring!
12-13 12:25:48.440  3253  3253 PackageManager Package com.android.incallui desires unavailable shared library com.sec.imslibrary; ignoring!
12-13 12:25:48.440  3253  3253 PackageManager Package com.android.incallui desires unavailable shared library TmoWfcUtils; ignoring!
12-13 12:25:48.445  3253  3253 PackageManager updateAllSharedLibrariesLPw failed: Package android requires unavailable shared library com.ipsec.client; failing!for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
        // NOTE: We ignore potential failures here during a system scan (like the rest of the commands above) because there's precious little we can do about it. A settings error is reported, though.
        //我們忽視了 系統掃描(像其余的命令以上)的潛在故障 因為沒有多少我們可以做的事。盡管報出了設置錯誤。
        adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */, false /* force dexopt */, false /* defer dexopt */);
    }
12-13 12:25:48.445  3253  3253 PackageManager ps : PackageSetting{1b14ab05 com.samsung.inputmethod/1000} instructionSet : arm
12-13 12:25:48.445  3253  3253 PackageManager ps : PackageSetting{2419cbb7 android/1000} instructionSet : arm

12-13 12:25:48.445  3253  3253 PackageManager Adjusting ABI for : com.sec.knox.switcher to armeabi-v7a
12-13 12:25:48.445  3253  3253 PackageManager Running dexopt on: /system/container/KnoxSwitcher/KnoxSwitcher.apk pkg=com.sec.knox.switcher isa=arm vmSafeMode=false interpret_only=false
12-13 12:25:48.500  3253  3253 PackageManager do mInstaller.dexopt : 0
12-13 12:25:48.500  3253  3253 PackageManager Time to dexopt: 0.056 seconds
12-13 12:25:48.500  3253  3253 PackageManager remove mDeferredDexOpt : Package{15cbec8c com.sec.knox.switcher}
12-13 12:25:48.500  3253  3253 PackageManager Skipping remove dex(arm) for : com.sec.knox.switcher
......
12-13 12:25:48.815  3253  3253 PackageManager Adjusting ABI for : com.android.settings to armeabi-v7a
12-13 12:25:48.815  3253  3253 PackageManager Running dexopt on: /system/priv-app/SecSettings/SecSettings.apk pkg=com.android.settings isa=arm vmSafeMode=false interpret_only=false
12-13 12:25:50.345  3253  3253 PackageManager do mInstaller.dexopt : 0
12-13 12:25:50.345  3253  3253 PackageManager Time to dexopt: 1.533 seconds
12-13 12:25:50.345  3253  3253 PackageManager remove mDeferredDexOpt : Package{2b0db67f com.android.settings}
12-13 12:25:50.345  3253  3253 PackageManager Skipping remove dex(arm) for : com.android.settings



      
    mSettings.getAllSharedUsersLPw()
    
⑧    mPackageUsage.readLP(); //我們知道了所有的package,讀取並更新它們的 上次使用時間
        readLP() 調用了convertUsageHistory();
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); //PMS掃描結束。
    Slog.i(TAG, "Time to scan packages: "  + ((SystemClock.uptimeMillis()-startTime)/1000f)  + " seconds");    //掃描PMS一共耗時

12-13 12:25:50.350  3253  3253 PackageManager Error reading history stats: java.io.FileNotFoundException: /data/system/usage-history.xml: open failed: ENOENT (No such file or directory)
12-13 12:25:50.350  3253  3253 PackageManager Time to scan packages: 43.669 seconds


    
    // If the platform SDK has changed since the last time we booted,
    // we need to re-grant app permission to catch any new ones that
    // appear.  This is really a hack, and means that apps can in some
    // cases get permissions that the user didn't initially explicitly
    // allow...  it would be nice to have some better way to handle
    // this situation.
    如果 自上次啟動以來,平台SDK版本有了變化, 那么我們需要對app重新授權。 這意味着,app可能會獲取到剛開始安裝時
    用戶沒有授予的權限... 應該找一個更好的方法來處理這種情況
    Slog.i(TAG, "Platform changed from " + mSettings.mInternalSdkPlatform + " to " + mSdkVersion + "; regranting permissions for internal storage");
    mSettings.mInternalSdkPlatform = mSdkVersion;
    updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
            | (regrantPermissions
                    ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
                    : 0));
    
    updatePermissionsLPw() -> grantPermissionsLPw()

12-13 12:25:50.390  3253  3253 PackageManager Unknown permission com.sec.factory.permission.ALLOWFTCLIENTCPOBIND in package com.sec.phone
12-13 12:25:50.390  3253  3253 PackageManager Unknown permission com.samsungtest.SlateTest.SLATE_DM_CMD in package com.sec.phone
12-13 12:25:50.390  3253  3253 PackageManager Unknown permission com.samsung.InputEventApp.permission.UTS_DM_CMD in package com.sec.phone
12-13 12:25:50.390  3253  3253 PackageManager Unknown permission com.sec.android.app.InputEventApp.permission.KEYSTRING in package com.sec.phone





    // If this is the first boot, and it is a normal boot, then we need to initialize the default preferred apps.
    如果這個第一次正常的啟動,我們需要初始化 默認app
    if (!mRestoredSettings && !onlyCore) {
        mSettings.readDefaultPreferredAppsLPw(this, 0);
    }
    
    // If this is first boot after an OTA, and a normal boot, then we need to clear code cache directories.
    如果這個OTA以后的第一次正常啟動,我們需要清除代碼緩存目錄
    if (!Build.FINGERPRINT.equals(mSettings.mFingerprint) && !onlyCore) {
        Slog.i(TAG, "Build fingerprint changed; clearing code caches");
        for (String pkgName : mSettings.mPackages.keySet()) {
            deleteCodeCacheDirsLI(pkgName);
        }
        mSettings.mFingerprint = Build.FINGERPRINT;
    }
    
    mSettings.updateInternalDatabaseVersion();    //更新內置的數據庫版本 
    
    // can downgrade to reader
    mSettings.writeLPr();    // 可降級
    
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis());   //PMS准備好了
    // synchronized (mPackages)
    // synchronized (mInstallLock)
    
    // Now after opening every single application zip, make sure they are all flushed. 
    // Not really needed, but keeps things nice and tidy.
    現在打開每一個app的zip包以后,確保他們都已經被緩存好了。
    不是真正的需要,但是 要保持一切已經被准備好了
    Runtime.getRuntime().gc();
    
12-13 12:25:50.555  3253  3253 SystemServer !@Boot: End PackageManagerService
12-13 12:25:50.555  3253  3253 SystemServer User Service
12-13 12:25:50.570  3253  3253 SystemServiceManager Starting com.android.server.lights.LightsService

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM