Android 優(yōu)化開機(jī)速度

1.1 ZygoteInit::preload

private static final CountDownLatch mConnectedSignal = new CountDownLatch(3);
static void preload() {
    Log.d(TAG, "begin preload");
    /* preload class and preload resource*/
    preloadResourcesThread = new Thread("preloadResources"){
             public void run() {
                    preloadResources(); //1.2
                    mConnectedSignal.countDown();
            }
     };
    preloadClasses(); //1.3
    waitForLatch(mConnectedSignal);
    preloadOpenGL();
    preloadSharedLibraries();// android攒驰、compiler_rt时呀、jnigraphics
    preloadTextResources();
    ...
    Log.d(TAG, "end preload");
}

1.2 ZygoteInit::preloadResources

/*
 * Load in commonly used resources, so they can be shared across
 * processes.
 *
 * These tend to be a few Kbytes, but are frequently in the 20-40K
 * range, and occasionally even larger.
*/

private static void preloadResources() {
    final VMRuntime runtime = VMRuntime.getRuntime();

    try {
        mResources = Resources.getSystem();
        mResources.startPreloading();
        if (PRELOAD_RESOURCES) {
            Log.i(TAG, "Preloading resources...");

            long startTime = SystemClock.uptimeMillis();
            TypedArray ar = mResources.obtainTypedArray(
                    com.android.internal.R.array.preloaded_drawables);
            int N = preloadDrawables(runtime, ar);
            ar.recycle();
            Log.i(TAG, "...preloaded " + N + " resources in "
                    + (SystemClock.uptimeMillis()-startTime) + "ms.");

            startTime = SystemClock.uptimeMillis();
            ar = mResources.obtainTypedArray(
                    com.android.internal.R.array.preloaded_color_state_lists);
            N = preloadColorStateLists(runtime, ar);
            ar.recycle();
            Log.i(TAG, "...preloaded " + N + " resources in "
                    + (SystemClock.uptimeMillis()-startTime) + "ms.");
        }
        mResources.finishPreloading();
    } catch (RuntimeException e) {
        Log.w(TAG, "Failure preloading resources", e);
    }
}

1.3 ZygoteInit::preloadClasses

/**
 * Performs Zygote process initialization. Loads and initializes
 * commonly used classes.
 *
 * Most classes only cause a few hundred bytes to be allocated, but
 * a few will allocate a dozen Kbytes (in one case, 500+K).
 */
private static void preloadClasses() {
    final VMRuntime runtime = VMRuntime.getRuntime();
    InputStream is = new FileInputStream(PRELOADED_CLASSES);
    Log.i(TAG, "Preloading classes...");
    long startTime = SystemClock.uptimeMillis();
    ...
    // Alter the target heap utilization.  With explicit GCs this
    // is not likely to have any effect.
    float defaultUtilization = runtime.getTargetHeapUtilization();
    runtime.setTargetHeapUtilization(0.8f);

    try {
        BufferedReader br = new BufferedReader(new InputStreamReader(is), 256);
        int count = 0;
        String line = null;
        final ArrayList<String> lines = new ArrayList<String>();
        while ((line = br.readLine()) != null) {
            // Skip comments and blank lines.
            line = line.trim();
            if (line.startsWith("#") || line.equals("")) {
                continue;
            }
            lines.add(line);
            count++;
        }
        Log.d(TAG, "Number of total Classes to preload: " + count);

        int start = 0;
        int end = start + count / 5;
        final List<String> list1 = lines.subList(start, end);
        Log.d(TAG,"Classes to load for thread1 " + start + "~"+end);
        loadClassAsync(list1, 1, startTime);//1.4
        preloadResourcesThread.start(); // 1.1 preloadResources

        start = end + 1;
        end = start + count / 7;
        final List<String> list2 = lines.subList(start, end);
        Log.d(TAG,"Classes to load for thread2 " + start + "~"+end);
        loadClassAsync(list2, 2, startTime); //1.4

        start = end + 1;
        end = count - 1;
        final List<String> list3 = lines.subList(start, end);
        Log.d(TAG,"Classes to load for thread3 " + start + "~"+end);
        loadClassImpl(list3, 3, startTime); //1.5
    } catch (IOException e) {
        Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
    } finally {
        // Restore default.
        runtime.setTargetHeapUtilization(defaultUtilization);
        // Fill in dex caches with classes, fields, and methods brought in by preloading.
        runtime.preloadDexCaches();
        // Bring back root. We'll need it later if we're in the zygote.
        ...
    }
}

1.4 ZygoteInit::loadClassAsync

private static void loadClassAsync(final List<String> list, final int index, final long startTime){
    new Thread(new Runnable() {
        public void run() {
                loadClassImpl(list, index, startTime);
                mConnectedSignal.countDown();
        }
    }, ("...proclass" + index)).start();
}

1.5 ZygoteInit::loadClassImpl

private static void loadClassImpl(final List<String> list, final int index, final long startTime){
    for (String line : list) {
        Class.forName(line, true, null);
}

2.1 PackageManagerService::main

方案1:多線程掃描不同的目錄(粒度較大)

private  final CountDownLatch mConnectedSignal = new CountDownLatch(5);
...
new Thread("scanPrivilegedAppDir"){
    @Override
    public void run() {
        long startTime = SystemClock.uptimeMillis();
        scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
                | PackageParser.PARSE_IS_SYSTEM_DIR
                | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
        Slog.w(TAG, "scanPrivilegedAppDir done,cost "+((SystemClock.uptimeMillis()-startTime)/1000f)+" seconds");
        mConnectedSignal.countDown();

    }
}.start();

2.2 PackageManagerService::scanDirLI

方案2:多線程以apk為粒度進(jìn)行掃描

private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
    final File[] files = dir.listFiles();
    ...
    Log.d(TAG, "start scanDirLI:"+dir);
    // use multi thread to speed up scanning
    int iMultitaskNum = SystemProperties.getInt("persist.pm.multitask", 6);
    Log.d(TAG, "max thread:" + iMultitaskNum);
    final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer(
            MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null;

    for (File file : files) {
        ...
        Runnable scanTask = new Runnable() {
            public void run() {
                try {
                    scanPackageTracedLI(ref_file, ref_parseFlags | PackageParser.PARSE_MUST_BE_APK,
                            ref_scanFlags, ref_currentTime, null);
                } catch (PackageManagerException e) {
                    Slog.w(TAG, "Failed to parse " + ref_file + ": " + e.getMessage());

                    // Delete invalid userdata apps
                    if ((ref_parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                            e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                        logCriticalInfo(Log.WARN, "Deleting invalid package at " + ref_file);
                        removeCodePathLI(ref_file);
                    }
                }
            }
        };

        if (dealer != null)
            dealer.addTask(scanTask);
        else
            scanTask.run();
    }

    if (dealer != null)
        dealer.waitAll();
    Log.d(TAG, "end scanDirLI:"+dir);
}

2.3 MultiTaskDealer構(gòu)造函數(shù)

private ThreadPoolExecutor mExecutor;
private int mTaskCount = 0;
private boolean mNeedNotifyEnd = false;
private Object mObjWaitAll = new Object();
private ReentrantLock mLock = new ReentrantLock();

public MultiTaskDealer(String name,int taskCount) {
    final String taskName = name;
    ThreadFactory factory = new ThreadFactory()
    {
        private final AtomicInteger mCount = new AtomicInteger(1);
        public Thread newThread(final Runnable r) {
            return new Thread(r, taskName + "-" + mCount.getAndIncrement());
        }
    };
    mExecutor = new ThreadPoolExecutor(taskCount, taskCount, 5, TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(), factory){
        protected void afterExecute(Runnable r, Throwable t) {
            if(t!=null) {
                t.printStackTrace();
            }
            MultiTaskDealer.this.TaskCompleteNotify(r);
            super.afterExecute(r,t);
        }
        protected void beforeExecute(Thread t, Runnable r) {
            if (DEBUG_TASK) Log.d(TAG, "start task");
            super.beforeExecute(t,r);
        }
    };
}

2.4 MultiTaskDealer::startDealer

public static MultiTaskDealer startDealer(String name,int taskCount) {
    MultiTaskDealer dealer = getDealer(name);
    if(dealer==null) {
        dealer = new MultiTaskDealer(name,taskCount);
        WeakReference<MultiTaskDealer> ref = new WeakReference<MultiTaskDealer>(dealer);
        map.put(name,ref);
    }
    return dealer;
}

2.5 MultiTaskDealer::addTask

public void addTask(Runnable task) {
    synchronized (mObjWaitAll) {
        mTaskCount+=1;
    }
    mExecutor.execute(task);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末织阳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杂拨,老刑警劉巖葬馋,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蒂教,居然都是意外死亡巍举,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門凝垛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來懊悯,“玉大人蜓谋,你說我怎么就攤上這事√糠郑” “怎么了桃焕?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)捧毛。 經(jīng)常有香客問我观堂,道長(zhǎng),這世上最難降的妖魔是什么呀忧? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任师痕,我火速辦了婚禮,結(jié)果婚禮上荐虐,老公的妹妹穿的比我還像新娘七兜。我一直安慰自己,他們只是感情好福扬,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布腕铸。 她就那樣靜靜地躺著,像睡著了一般铛碑。 火紅的嫁衣襯著肌膚如雪狠裹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天汽烦,我揣著相機(jī)與錄音涛菠,去河邊找鬼。 笑死撇吞,一個(gè)胖子當(dāng)著我的面吹牛俗冻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牍颈,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼迄薄,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了煮岁?” 一聲冷哼從身側(cè)響起讥蔽,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎画机,沒想到半個(gè)月后冶伞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡步氏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年响禽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡金抡,死狀恐怖瀑焦,靈堂內(nèi)的尸體忽然破棺而出腌且,到底是詐尸還是另有隱情梗肝,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布铺董,位于F島的核電站巫击,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏精续。R本人自食惡果不足惜坝锰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望重付。 院中可真熱鬧顷级,春花似錦、人聲如沸确垫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽删掀。三九已至翔冀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間披泪,已是汗流浹背纤子。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留款票,地道東北人控硼。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像艾少,于是被迫代替她去往敵國(guó)和親卡乾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容