Android 优化开机速度

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 lines = new ArrayList();
        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 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 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 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 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 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为粒度进行扫描

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构造函数

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(), 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 ref = new WeakReference(dealer);
        map.put(name,ref);
    }
    return dealer;
}

2.5 MultiTaskDealer::addTask

public void addTask(Runnable task) {
    synchronized (mObjWaitAll) {
        mTaskCount+=1;
    }
    mExecutor.execute(task);
}

你可能感兴趣的:(Android 优化开机速度)