Android提高启动速度


大家都知道启动速度慢是智能操作系统的一个通病,Android也不例外,启动速度大概在1分钟左右,虽然日本有一个叫quick boot的一秒启动android的产品,但是毕竟是旁门左道。所以从常规来提高android的启动速度成了大家研究的重点,也是难点。下面将初步研究的一下经验跟大家分享一下。

首先看一下android系统的启动流程:

bootloader
          引导程序

kernel
         内核

init
          init
初始化(这个大家都比较熟悉了,不要多说)

      • loads several daemons and services, including zygote
      • see /init.rc and init.<platform>.rc
zygote

这个是占用时间最多的,重点修理对象
      • preloads classes
        装载了一千多个类,妈呀!!!
      • starts package manager 扫描package(下面详细介绍)

service manager

      • start services (启动多个服务)

从实际的测试数据来看,有两个地方时最耗时间的,一个是zygote的装载一千多个类和初始化堆栈的过程,用了20秒左右。另一个是扫描

/system/app,
    /system/framework,
    /data/app,
    /data/app-private.

这几个目录下面的package用了大概10秒,所以我们重点能够修理的就是这两个老大的。

一、首先是调试工具的使用,可以测试哪些类和那些过程占用了多少时间,

主要工具为

stopwatch

Message loggers

grabserial

printk times

logcat 

Android自带

bootchart 

strace

    AOSP的一部分(Eclair及以上版本)

使用例子

在init.rc中为了调试zygote


service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server改为
service zygote /system/xbin/strace -tt -o/data/boot.strace /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
 


method tracer*

ftrace*

详细使用可看提供的文档和网页介绍

上面的工具如果不用详细的分析不一定都用到,也可以使用logcat就可以,在代码中加一点计算时间和一些类的调试信息也可以达到很好效果。

二、zygote 装载1千多个类

首先,我们可以添加一点调试信息,以获得具体转载情况。

diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 404c513..f2b573c 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -259,6 +259,8 @@ public class ZygoteInit {
         } else {
             Log.i(TAG, "Preloading classes...");
             long startTime = SystemClock.uptimeMillis();
+            long lastTime = SystemClock.uptimeMillis();
+            long nextTime = SystemClock.uptimeMillis();

             // Drop root perms while running static initializers.
             setEffectiveGroup(UNPRIVILEGED_GID);
@@ -292,12 +294,24 @@ public class ZygoteInit {
                         if (Config.LOGV) {
                             Log.v(TAG, "Preloading " + line + "...");
                         }
+                        //if (count%5==0) {
+                        //    Log.v(TAG, "Preloading " + line + "...");
+                        //}
+                        Log.v(TAG, "Preloading " + line + "...");
                         Class.forName(line);
+              nextTime = SystemClock.uptimeMillis();
+   if (nextTime-lastTime >50) {
+       Log.i(TAG, "Preloading " + line + "... took " + (nextTime-lastTime) + "ms.");
+   }
+   lastTime = nextTime;
+   
                         if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
                             if (Config.LOGV) {
                                 Log.v(TAG,
                                     " GC at " + Debug.getGlobalAllocSize());
                             }
+                            Log.i(TAG,
+                               " GC at " + Debug.getGlobalAllocSize());
                             runtime.gcSoftReferences();
                             runtime.runFinalizationSync();
                             Debug.resetGlobalAllocSize();

上面+代表添加的代码,这样就可以很容易的得到在装载类的过程中具体装载了哪些类,耗费了多久。具体装载的类在文件platform/frameworks/base/      preloaded-classes

内容类似:

android.R$styleable
android.accounts.AccountMonitor
android.accounts.AccountMonitor$AccountUpdater
android.app.Activity
android.app.ActivityGroup
android.app.ActivityManager$MemoryInfo$1
android.app.ActivityManagerNative
android.app.ActivityManagerProxy
android.app.ActivityThread
android.app.ActivityThread$ActivityRecord
android.app.ActivityThread$AppBindData
android.app.ActivityThread$ApplicationThread
android.app.ActivityThread$ContextCleanupInfo
android.app.ActivityThread$GcIdler
android.app.ActivityThread$H
android.app.ActivityThread$Idler

而这个文件是由文件WritePreloadedClassFile.java中的WritePreloadedClassFile类自动生成

/**


* Writes /frameworks/base/preloaded-classes. Also updates


* {@link LoadedClass#preloaded} fields and writes over compiled log file.


*/

public class WritePreloadedClassFile

    /**

     * Preload any class that take longer to load than MIN_LOAD_TIME_MICROS us.

     */

static final int MIN_LOAD_TIME_MICROS = 1250;//这个代表了装载时间小于1250us1.25ms的类将不予装载,也许可以改这个参数减少一下类的装载


//
这里可以看到什么样的类会被装载


A:
启动必须装载的类,比如系统级的类


B
:刚才说的装载时间大于1.25ms的类


C
:被使用一次以上或被应用装载的类

仔细看看筛选类的具体实现,可以帮助我们认识哪些类比较重要,哪些可以去掉。

筛选规则是

第一  isPreloadable,

    /**Reports if the given class should be preloaded. */
    public static boolean isPreloadable(LoadedClass clazz) {

        return clazz.systemClass && !EXCLUDED_CLASSES.contains(clazz.name);

    }

意思是指除了EXCLUDED_CLASSES包含的类之外的所有系统装载的类。

EXCLUDED_CLASSES包含

    /**
     * Classes which we shouldn't load from the Zygote.
     */
    private static final Set<String> EXCLUDED_CLASSES
            = new HashSet<String>(Arrays.asList(
        // Binders
        "android.app.AlarmManager",
        "android.app.SearchManager",
        "android.os.FileObserver",
        "com.android.server.PackageManagerService$AppDirObserver",

        // Threads
        "android.os.AsyncTask",
        "android.pim.ContactsAsyncHelper",
        "java.lang.ProcessManager"
    ));

目前是跟Binders跟Threads有关的不会被预装载。



第二   clazz.medianTimeMicros() > MIN_LOAD_TIME_MICROS装载时间大于1.25ms。

第三  names.size() > 1 ,既是被processes一次以上的。

上面的都是指的system class,另外还有一些application class需要被装载

规则是fromZygote而且不是服务

proc.fromZygote() && !Policy.isService(proc.name)


fromZygote指的除了com.android.development的zygote类

    public boolean fromZygote() {
        return parent != null && parent.name.equals("zygote")
                && !name.equals("com.android.development");
    }


/除了常驻内存的服务


    /**
     * Long running services. These are restricted in their contribution to the
     * preloader because their launch time is less critical.
     */
    // TODO: Generate this automatically from package manager.
    private static final Set<String> SERVICES = new HashSet<String>(Arrays.asList(
        "system_server",
        "com.google.process.content",
        "android.process.media",
        "com.android.bluetooth",
        "com.android.calendar",
        "com.android.inputmethod.latin",
        "com.android.phone",
        "com.google.android.apps.maps.FriendService", // pre froyo
        "com.google.android.apps.maps:FriendService", // froyo
        "com.google.android.apps.maps.LocationFriendService",
        "com.google.android.deskclock",
        "com.google.process.gapps",
        "android.tts"
    ));

好了。要转载的就是这些类了。虽然preloaded-classes是在下载源码的时候已经确定了的,也就是对我们来说WritePreloadedClassFile类是没用到的,我们可以做的就是在preloaded-classes文件中,把不预装载的类去掉,试了把所有类去掉,启动确实很快跳过那个地方,但是启动HOME的时候就会很慢了。所以最好的方法就是只去掉那些没怎么用到的,不过要小心处理。至于该去掉哪些,还在摸索,稍后跟大家分享。有兴趣的朋友可以先把preloaded-classes这个文件里面全部清空,启动快了很多,但在启动apk的时候会慢了点。当然了,也可以把android相关的类全部去掉,剩下java的类,试过了也是可以提高速度。

  • 1
  • 2
  • 下一页

相关内容