Android的优化.doc_第1页
Android的优化.doc_第2页
Android的优化.doc_第3页
Android的优化.doc_第4页
Android的优化.doc_第5页
已阅读5页,还剩41页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Android的优化1 General1 编译release版本2 除报错信息外,去除所有的打印信息,对于部分常规错误,也可以关闭打印信息3 Config.javapublic static final boolean LOGD = true; 改为:public static final boolean LOGD = false;很多打印信息都通过判断LOGD来决定是否输出。很可能改成release版本后这条就无效了。4 减少不必要的APK安装5 缩减开机动画和铃声6 超频?7 AT和MODEM的交互的优化8 去除proload-classes9 裁减服务10 先进lounch,再加载东西11 运行时把有些刷新时间拉长点12 动态壁纸去掉13 TP校准apk去掉14 视频播放器保留一个即可15 去掉一些定时器16 配置文件去掉不需要的配置,其他都关闭debug17 优化屏幕刷新速度18 调整堆的大小2 开机速度2.1 浅谈Android开机启动速度优化(含应用程序启动速度优化)/jackyu613/article/details/6044297众所周知Android开机启动速度较慢,于是如何加快启动速度便成为一个值得讨论的问题。在查阅过许多资料后(特别是Google Group的android-platform),我整理总结出下面几点基本看法。Android开机启动耗时较多的部分有2个,分别是preload classes和scan packages。这里又数preload classes最为耗时,在我的机子上一般需要13秒左右。关于preload classes的优化,可以参见/thread-29953-1-1.html。这篇帖子并没有给出如何优化preloaded-classes list的具体取舍。实际上,在看过google group众多关于preload class的主题后,基本可以确定以下事实: 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,否则我们不能看到我们期望加速启动效果。 关于scan packages的问题。同样参考上面提到的那篇帖子,我们从中可以知道一个事实:越少的apk安装,越短的启动时间。事实上确实如此,apk安装的多少的确影响开机速度,但相比而言,scan packages所花费的时间远没有preload classe多。似乎这里没有多少油水可榨,但起码我们知道了:尽量减少产品中预置的apk数量可以提升启动速度(哪怕精简到极致也许只节省了2s)。最后,关于那篇帖子中提到的start services阶段,我认为虽然此阶段确实需要消耗可观的时间,但是正如文中提到的那样,优化这些services其实就是剔除我们不需要的一些services,而且不仅仅是修改SystemServer.java的问题,任何使用到被优化剔除掉的服务的代码都必须加以修改,否则系统肯定是起不来的。这样工作量大,而且难度也不小,并且有一定风险。因此对这些services的优化要慎之又慎。那么加快启动速度是不是就没有办法了呢?也不是。除了硬件上的改动,在软件上使用BLCR技术也可以解决这个问题。在/shuaiff/archive/2010/09/19/5894646.aspx这篇文章中比较详细的介绍了BLCR技术在Android上的应用情况。个人认为应用BLCR不复杂,值得我们尝试。在此我认为同时有必要提一下应用程序启动速度加速的问题。用过Android的都会发现,第一次启动某个应用程序时比较慢,但只要不关机重启,大部分情况下以后再次启动就明显的要快许多。因此我们很容易想到一种办法,即“预加载”我们的应用程序一次,那么下次用户再次启动我们时不就快了吗?我们首先明确一点:任何“预加载”的想法都是不切实际的。先不讨论实施在技术上的可能性,我们只要看一下Android的Activity生命周期管理就应该明白,就算你通过某种方式“预加载”了你的某个Activity,你也不能确保在用户真正要求开始运行它的时候,你所“预加载”的Activity还存在,因为Android很可能在你为“预加载”第一次启动Activity后的不久就将它gc掉了。依靠一个不可靠的技术,显然是不明智的。那么还有没有别的办法呢?答案是有的,但是只在少数情况下才有一定意义。在源码的frameworks/base/core/res/res/values/arrays.xml中,我们可以看到有名为“preloaded_drawables”的项,其中列出的是Android在启动时预加载的图形资源,这样在某个应用程序需要这些图形资源时就不必再加载了。如果我们某个应用程序包含大量的图形资源,那么我们可以将其加入到这个preloaded_drawables项中以加快我们应用程序的启动速度。但是这样有一个显而易见的弊端:同preload classes一样,不是每个应用程序都需要所有预加载的图形资源,这些冗余的资源反而占据了应用程序进程的内存空间。因此,这种技术实际应用的局限性较大,仅限于这样一种情况:某个设备只运行固定的几个应用程序,而且这些应用程序包含大量的图形资源需要加载。但这样会是一个什么设备呢?好了,到此基本上把我这两天研究的心得写出来了。限于认识水平有限,如果文中有误或者哪位能有更好的想法,欢迎在下面留言:)如果以后我又有心得,会再更新此文。2.2 Android重量级开发之-提高android启动速度研究 首发,作者:T 大家都知道启动速度慢是智能操作系统的一个通病,Android也不例外,启动速度大概在1分钟左右,虽然日本有一个叫quick boot的一秒启动android的产品,但是毕竟是旁门左道。所以从常规来提高android的启动速度成了大家研究的重点,也是难点。下面将初步研究的一下经验跟大家分享一下。首先看一下android系统的启动流程:bootloader 引导程序kernel 内核init init初始化(这个大家都比较熟悉了,不要多说)loads several daemons and services, including zygote see /init.rc and init.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 参考/Grabserialprintk times 参考/Printk_Times logcat Android自带 bootchart 参考/Bootchart 和 /Bootchartstrace AOSP的一部分(Eclair及以上版本)使用例子在init.rc中为了调试zygoteservice 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.javaindex 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$styleableandroid.accounts.AccountMonitorandroid.accounts.AccountMonitor$AccountUpdaterandroid.app.Activityandroid.app.ActivityGroupandroid.app.ActivityManager$MemoryInfo$1android.app.ActivityManagerNativeandroid.app.ActivityManagerProxyandroid.app.ActivityThreadandroid.app.ActivityThread$ActivityRecordandroid.app.ActivityThread$AppBindDataandroid.app.ActivityThread$ApplicationThreadandroid.app.ActivityThread$ContextCleanupInfoandroid.app.ActivityThread$GcIdlerandroid.app.ActivityThread$Handroid.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;/这个代表了装载时间小于1250us即1.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(); 意思是指除了EXCLUDED_CLASSES包含的类之外的所有系统装载的类。EXCLUDED_CLASSES包含 /* * Classes which we shouldnt load from the Zygote. */ private static final Set EXCLUDED_CLASSES = new HashSet(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()fromZygote指的除了com.android.development的zygote类 public boolean fromZygote() return parent != null & .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 SERVICES = new HashSet(Arrays.asList( system_server, cess.content, cess.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, cess.gapps, android.tts );好了。要转载的就是这些类了。虽然preloaded-classes是在下载源码的时候已经确定了的,也就是对我们来说WritePreloadedClassFile类是没用到的,我们可以做的就是在preloaded-classes文件中,把不预装载的类去掉,试了把所有类去掉,启动确实很快跳过那个地方,但是启动HOME的时候就会很慢了。所以最好的方法就是只去掉那些没怎么用到的,不过要小心处理。至于该去掉哪些,还在摸索,稍后跟大家分享。有兴趣的朋友可以先把preloaded-classes这个文件里面全部清空,启动快了很多,但在启动apk的时候会慢了点。当然了,也可以把android相关的类全部去掉,剩下java的类,试过了也是可以提高速度。三,系统服务初始化和package 扫描在启动系统服务的init2()时会启动应用层(Java层)的所有服务。 public static void main(String args) System.loadLibrary(android_servers); init1(args); /init1 初始化,完成之后会回调init2() 在init2()中会启动一个线程来启动所有服务public static final void init2() Log.i(TAG, Entered the Android system server!); Thread thr = new ServerThread(); thr.setName(android.server.ServerThread); thr.start(); class ServerThread extends Thread 。public void run() 。关键服务: ServiceManager.addService(entropy, new EntropyService();ServiceManager.addService(Context.POWER_SERVICE, power); context = ActivityManagerService.main(factoryTest); ServiceManager.addService(telephony.registry, new TelephonyRegistry(context); PackageManagerService.main(context, factoryTest != SystemServer.FACTORY_TEST_OFF);/apk扫描的服务 ServiceManager.addService(Context.ACCOUNT_SERVICE, new AccountManagerService(context); ContentService.main(context, factoryTest = SystemServer.FACTORY_TEST_LOW_LEVEL); battery = new BatteryService(context); ServiceManager.addService(battery, battery); hardware = new HardwareService(context); ServiceManager.addService(hardware, hardware); AlarmManagerService alarm = new AlarmManagerService(context); ServiceManager.addService(Context.ALARM_SERVICE, alarm);ServiceManager.addService(Context.SENSOR_SERVICE, new SensorService(context);WindowManagerService.main(context, power, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL); ServiceManager.addService(Context.WINDOW_SERVICE, wm);上面这些都是关键服务,不建议进行裁剪。下面的这些不是很关键,可以进行裁剪,当是必须相应的修改framework部分的代码,工作量比较大和复杂。我去掉了20个服务,大概需要相应修改大概20多个文件。 statusBar = new StatusBarService(context); ServiceManager.addService(statusbar, statusBar); ServiceManager.addService(clipboard, new ClipboardService(context); imm = new InputMethodManagerService(context, statusBar); ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm); ServiceManager.addService(netstat, new NetStatService(context); connectivity = ConnectivityService.getInstance(context); ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity); ServiceManager.addService(Context.ACCESSIBILITY_SERVICE, new AccessibilityManagerService(context); notification = new NotificationManagerService(context, statusBar, hardware); ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification); ServiceManager.addService(mount, new MountService(context); ServiceManager.addService(DeviceStorageMonitorService.SERVICE, new DeviceStorageMonitorService(context); ServiceManager.addService(Context.LOCATION_SERVICE, new LocationManagerService(context); ServiceManager.addService( Context.SEARCH_SERVICE, new SearchManagerService(context) ); if (INCLUDE_DEMO) Log.i(TAG, Installing demo data.); (new DemoThread(context).start(); Intent intent = new Intent().setComponent(new ComponentName( com.google.android.server.checkin, com.google.android.server.checkin.CheckinService); ServiceManager.addService(checkin, new FallbackCheckinService(context); wallpaper = new WallpaperManagerService(context); ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper); ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context); headset = new HeadsetObserver(context); dock = new DockObserver(context, power); ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context); ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget);package 扫描部分,整个流程为下图所示:最终的zip文件(apk)读取是在下面这两个函数:/* Open the specified file read-only. We memory-map the entire thing and* close the file before returning.*/status_t ZipFileRO:open(const char* zipFileName) int fd = -1; off_t length; assert(mFileMap = NULL);LOGD(opening zip %sn, zipFileName); /* * Open and map the specified file. */ fd = :open(zipFileName, O_RDONLY); if (fd 0) LOGW(Unable to open zip %s: %sn, zipFileName, strerror(errno); return NAME_NOT_FOUND; length = lseek(fd, 0, SEEK_END); if (length create(zipFileName, fd, 0, length, true) LOGW(Unable to map %s: %sn, zipFileName, strerror(errno); close(fd); return UNKNOWN_ERROR; mFd = fd; /* * Got it mapped, verify it and create data structures for fast access. */ if (!parseZipArchive() mFileMap-release(); mFileMap = NULL; return UNKNOWN_ERROR; LOGD(done opening zipn); return OK;/* Parse the Zip archive, verifying its contents and initializing internal* data structures.*/bool ZipFileRO:parseZipArchive(void)#define CHECK_OFFSET(_off) if (unsigned int) (_off) = maxOffset) LOGE(ERROR: bad offset %u (max %d): %sn, (unsigned int) (_off), maxOffset, #_off); goto bail; const unsigned char* basePtr = (const unsigned char*)mFileMap-getDataPtr(); const unsigned char* ptr; size_t length = mFileMap-getDataLength(); bool result = false; unsigned int i, numEntries,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论