Android开机启动慢,是一个众所周知的问题。
优化方向:
1、预加载的优化
在网上看的资料,对于开机启动来说,耗时最久的是preload classes和scan packages。所以第一个优化方向就是预加载类。
这是在网上看的
· preloaded-classes list中预加载的类位于dalvik zygote进程的heap中。在zygote衍生一个新的dalvik进程后,新进程只需加载heap中没有预加载的类(这些后加载进来的类成为该进程所private独有的),这样便加快了应用程序的启动速度。实际上这是一种以空间换时间的办法,因为几乎没有一个应用程序能够使用到所有的预加载类,必定有很多类对于该应用程序来说是冗余的。但是也正如Google所说,智能手机开机远没有启动应用程序频繁——用户开机一次,但直到下次再开机之前可能要运行多个应用程序。因此牺牲一点启动时间来换取应用程序加载时的较快速度是合算的。
· preloaded-classes list已经是Google Android工程师使用众多测试工具分析,加以手动微调后形成的最优化预加载列表,涵盖了智能机上最长见的应用类型所需要的各种类。很难想象我们自己能够有什么手段能够获得比这样更优的一个预加载列表。所以,除非你的Android系统是被移植到非智能手机设备上使用(例如MID、EBOOK,可以不需要Telephony相关的类),不建议去“优化”preloaded-classes list。 在zygote中单起一个线程来做preload,是否可行?答案是否定的。首先在zygote中不可以新开线程,其次,就算新开一个线程,在目前智能机硬件条件下(单核CPU),除非有频繁大量的存储IO,否则我们不能看到我们期望加速启动效果。
上面说了“但是也正如Google所说,智能手机开机远没有启动应用程序频繁——用户开机一次,但直到下次再开机之前可能要运行多个应用程序。因此牺牲一点启动时间来换取应用程序加载时的较快速度是合算的。”但是对于机顶盒来说,这就反而不是这样了,机顶盒的开关机比较频繁。
预加载优化方向:
(1)、将预加载放置到system_server 启动之后。
对于几个preload来说,最耗时的是类的预加载,所以我们可以把
preloadclass单独剥离出来一个线程,并将其放到system_server之后,会有一定的启动速度提升。
如此下代码所示:
public static class PreloadClassThread extends Thread {
public void run() {
preloadClasses();
}
}
static void preload() {
// preloadClasses(); // Delay preloadClasses
preloadResources();
preloadOpenGL();
}
public static void main(String argv[]) {
try {
.....省略无关代码
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
.....省略无关代码
if (argv[1].equals("start-system-server")) {
startSystemServer();
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
Log.i(TAG, "Accepting command socket connections");
Thread preloadclass = new PreloadClassThread();
preloadclass.start();
(2)、加载的时候要顺序加载 ,我们可以改为多线程同步来执行。
preloadClasses();
preloadResources();
preloadOpenGL();
android 原本的加载方式如下:
static void preload() {
preloadClasses();
preloadResources();
preloadOpenGL();
}
我们修改为:
static void concurrent_preload() {
Thread preloadclass = new PreloadClassThread();
Thread preloadres = new PreloadResThread();
preloadclass.start();
preloadres.start();
try {
preloadclass.join();
preloadres.join();
} catch (InterruptedException ex) {
Log.e(TAG, "concurrent_preload join() InterruptedException error ", ex);
}
preloadOpenGL();
}
我们可以加一些属性来控制是否要跳过预加载、选择哪种方式预加载。
scan packages的优化就是减少不必要的APK了。
2、去除SELinux
SELinux是一种强制访问控制(MAC)系统。有以下两种模式:
Enforcing:使能状态,所有违反policy的动作都会被拒绝。
Permissive:宽容模式,违反policy的动作不会被拒绝,只会警告。
开启SELinux,在kernel和init进程都会有相关的一些操作,所以会对开机速度有一定的影响。如果对于机顶盒这种的话,其实看情况也是可以关掉的。
关闭方法对于各个厂商可能有些不同,一般是在bootargs里面把其配置为关闭即可。
3、开机动画
其实很多时候,盒子已经到了launcher启动的阶段,但是开机动画还没播放完。优化开机动画的显示时间,可以减少很多开机时间,但是出于盒子本身的功能来说,开机动画一般用作广告,所以这个可以优化的空间比较小。手机倒是可以这样子优化,这就没什么好说的了,修改bootanimation.zip中的开机动画时间即可。
4、减少不必要的service
这里说的是两种不同概念的service:
1是由init进程来启动的service,这个需要裁剪init.xxx.rc中不需要的service,因为init进程启动太多service的话,可能会导致zygote和systemServer启动速度受到影响。
2是system_server启动的java层面的service,像机顶盒的话telephony,location这样的服务一般也可以不要了。
5、修改为odex方式
这是以空间换取时间的优化方式。
1、在自己device目录 下Bordconfig.mk中加入
WITH_DEXPREOPT=true
2、在相同目录下修改system.prop
dalvik.vm.verify-bytecode=true