如何测试android 开机启动appapp启动速度

比特客户端
您的位置:
详解大数据
详解大数据
详解大数据
详解大数据
揭秘Android手机变慢的三大原因与对策
关键字:App
app应用中心
  很多用户都感觉自己的手机使用一段时间久变得越来越慢,那么到底影响手机速度的因素有哪些?如何为手机加速呢?下面小编就为大家来揭秘一下手机变慢的三大原因及其对策。
  原因一:开机自启动程序导致手机变慢
  大量会开机自启动,导致手机内存被大量占用,因此手机会变慢。但是用户很难自己找到哪些应用开机自启动,所以也无法禁止这些自启动的应用。
  对策:一键ROOT大师开机加速。使用一键ROOT大师的的开机加速功能的前提是手机获得ROOT权限,获取的过程也十分简单,直接安装一键ROOT大师点击立即获取ROOT权限,成功后就可以再授权管理中看到已经允许开机启动的应用和被禁止启动的应用,用户可以根据自己的需要手动的选择是否允许这些应用开机启动。
  原因二:后台进程影响手机速度
  看似一个应用已经通过其自带的“退出”功能关闭了,可实际上却仍在手机后台驻留。而这也是普通用户无法发现的问题,这些驻留的应用有的是为了push新消息、等待新任务,而有一些完全没有驻留后台的必要,所以需要关闭这些后台进程。
  对策:使用一键清理大师的一键加速功能释放内存。通过一键清理大师中的“内存加速”功能可以看到当前用户进程和系统进程,勾选要关闭进程,点击一键加速,即可完成内存的释放,对于一些手机内置应用来说与系统应用一起被驻留在内存中,影响手机速度。可以通过手动关闭,也可以根据其建议进行关闭。
  原因三:大量的预装软件占用内存影响手机速度
  很多在出厂时都已经预装大量的预装软件,这种现象在国产手机中非常常见,大量的无用预装软件不仅无法卸载而且还占用了手机的大量内存,影响手机的运行速度,使手机速度变卡变慢。
  对策:通过一键ROOT大师获取手机ROOT权限,在授权管理中卸载手机预装的应用,有效解决系统内存占用问题,释放内存空间,提升手机运行速度和系统流畅度。
  小编测试,经过以上方法小编手机内存占用从80%降低至46%,整整优化将近一半。手机日常使用也再无卡顿等问题,另外小编提醒各位手机用户,如果你的机型不能用手机版的一键ROOT大师获取ROOT权限,那么可以使用电脑版的一键ROOT大师进行ROOT,成功率更高,而且操作也很方便。
[ 责任编辑:张然 ]
甲骨文的云战略已经完成第一阶段…
软件信息化周刊
比特软件信息化周刊提供以数据库、操作系统和管理软件为重点的全面软件信息化产业热点、应用方案推荐、实用技巧分享等。以最新的软件资讯,最新的软件技巧,最新的软件与服务业内动态来为IT用户找到软捷径。
商务办公周刊
比特商务周刊是一个及行业资讯、深度分析、企业导购等为一体的综合性周刊。其中,与中国计量科学研究院合力打造的比特实验室可以为商业用户提供最权威的采购指南。是企业用户不可缺少的智选周刊!
比特网络周刊向企业网管员以及网络技术和产品使用者提供关于网络产业动态、技术热点、组网、建网、网络管理、网络运维等最新技术和实用技巧,帮助网管答疑解惑,成为网管好帮手。
服务器周刊
比特服务器周刊作为比特网的重点频道之一,主要关注x86服务器,RISC架构服务器以及高性能计算机行业的产品及发展动态。通过最独到的编辑观点和业界动态分析,让您第一时间了解服务器行业的趋势。
比特存储周刊长期以来,为读者提供企业存储领域高质量的原创内容,及时、全面的资讯、技术、方案以及案例文章,力求成为业界领先的存储媒体。比特存储周刊始终致力于用户的企业信息化建设、存储业务、数据保护与容灾构建以及数据管理部署等方面服务。
比特安全周刊通过专业的信息安全内容建设,为企业级用户打造最具商业价值的信息沟通平台,并为安全厂商提供多层面、多维度的媒体宣传手段。与其他同类网站信息安全内容相比,比特安全周刊运作模式更加独立,对信息安全界的动态新闻更新更快。
新闻中心热点推荐
新闻中心以独特视角精选一周内最具影响力的行业重大事件或圈内精彩故事,为企业级用户打造重点突出,可读性强,商业价值高的信息共享平台;同时为互联网、IT业界及通信厂商提供一条精准快捷,渗透力强,覆盖面广的媒体传播途径。
云计算周刊
比特云计算周刊关注云计算产业热点技术应用与趋势发展,全方位报道云计算领域最新动态。为用户与企业架设起沟通交流平台。包括IaaS、PaaS、SaaS各种不同的服务类型以及相关的安全与管理内容介绍。
CIO俱乐部周刊
比特CIO俱乐部周刊以大量高端CIO沙龙或专题研讨会以及对明星CIO的深入采访为依托,汇聚中国500强CIO的集体智慧。旨为中国杰出的CIO提供一个良好的互融互通 、促进交流的平台,并持续提供丰富的资讯和服务,探讨信息化建设,推动中国信息化发展引领CIO未来职业发展。
IT专家新闻邮件长期以来,以定向、分众、整合的商业模式,为企业IT专业人士以及IT系统采购决策者提供高质量的原创内容,包括IT新闻、评论、专家答疑、技巧和白皮书。此外,IT专家网还为读者提供包括咨询、社区、论坛、线下会议、读者沙龙等多种服务。
X周刊是一份IT人的技术娱乐周刊,给用户实时传递I最新T资讯、IT段子、技术技巧、畅销书籍,同时用户还能参与我们推荐的互动游戏,给广大的IT技术人士忙碌工作之余带来轻松休闲一刻。
微信扫一扫
关注Chinabyte博客访问: 2678110
博文数量: 664
博客积分: 13321
博客等级: 上将
技术积分: 8581
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Android平台
重量级开发之提高启动速度研究
& && && && && && && && && && && &&&首发,作者:
& &&&大家都知道启动速度慢是智能操作系统的一个通病,Android也不例外,启动速度大概在1分钟左右,虽然日本有一个叫quick boot的一秒启动android的产品,但是毕竟是旁门左道。所以从常规来提高android的启动速度成了大家研究的重点,也是难点。下面将初步研究的一下经验跟大家分享一下。
首先看一下android系统的启动流程:
bootloader&
& && && & 引导程序
& && && &内核
& && && & init初始化(这个大家都比较熟悉了,不要多说)
loads several daemons and services, including zygote
see /init.rc and init.&platform&.rc
这个是占用时间最多的,重点修理对象
preloads classes&
装载了一千多个类,妈呀!!!
starts package manager&扫描package(下面详细介绍)
service manager
start services&(启动多个服务)
从实际的测试数据来看,有两个地方时最耗时间的,一个是zygote的装载一千多个类和初始化堆栈的过程,用了20秒左右。另一个是扫描
/system/app,
& & /system/framework,
& & /data/app,
& & /data/app-private.
这几个目录下面的package用了大概10秒,所以我们重点能够修理的就是这两个老大的。
一、首先是调试工具的使用,可以测试哪些类和那些过程占用了多少时间,
主要工具为
Message loggers
grabserial&
printk times&参考
Android自带
bootchart&参考&和
& & 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*
详细使用可看提供的文档和网页介绍
上面的工具如果不用详细的分析不一定都用到,也可以使用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 = nextT
& && && && && && && && & 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;//这个代表了装载时间小于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(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的类,试过了也是可以提高速度。
三,系统服务初始化和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;
& & assert(mFileMap == NULL);
LOGD("opening zip '%s'\n", zipFileName);
& &&&* Open and map the specified file.
& & fd = ::open(zipFileName, O_RDONLY);
& & if (fd & 0) {
& && &&&LOGW("Unable to open zip '%s': %s\n", zipFileName, strerror(errno));
& && &&&return NAME_NOT_FOUND;
& & length = lseek(fd, 0, SEEK_END);
& & if (length & 0) {
& && &&&close(fd);
& && &&&return UNKNOWN_ERROR;
& & mFileMap = new FileMap();
& & if (mFileMap == NULL) {
& && &&&close(fd);
& && &&&return NO_MEMORY;
& & if (!mFileMap-&create(zipFileName, fd, 0, length, true)) {
& && &&&LOGW("Unable to map '%s': %s\n", zipFileName, strerror(errno));
& && &&&close(fd);
& && &&&return UNKNOWN_ERROR;
& &&&* Got it mapped, verify it and create data structures for fast access.
& & if (!parseZipArchive()) {
& && &&&mFileMap-&release();
& && &&&mFileMap = NULL;
& && &&&return UNKNOWN_ERROR;
LOGD("done opening zip\n");
& & 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): %s\n",& && && && && && && &\
& && && && && & (unsigned int) (_off), maxOffset, #_off);& && && && && && & \
& && && && && && && && && && && && && && && && && && && && && && &\
& && &&&}& && && && && && && && && && && && && && && && && && && && && && & \
& & const unsigned char* basePtr = (const unsigned char*)mFileMap-&getDataPtr();
& & const unsigned char*
& & size_t length = mFileMap-&getDataLength();
& & bool result =
& & unsigned int i, numEntries, cdO
& &&&* The first 4 bytes of the file will either be the local header
& &&&* signature for the first file (kLFHSignature) or, if the archive doesn't
& &&&* have any files in it, the end-of-central-directory signature
& &&&* (kEOCDSignature).
& & val = get4LE(basePtr);
& & if (val == kEOCDSignature) {
& && &&&LOGI("Found Zip archive, but it looks empty\n");
& & } else if (val != kLFHSignature) {
& && &&&LOGV("Not a Zip archive (found 0x%08x)\n", val);
& &&&* Find the EOCD.&&We'll find it immediately unless they have a file
& &&&* comment.
& & ptr = basePtr + length - kEOCDL
& & while (ptr &= basePtr) {
& && &&&if (*ptr == (kEOCDSignature & 0xff) && get4LE(ptr) == kEOCDSignature)
& && && && &
& && &&&ptr--;
& & if (ptr & basePtr) {
& && &&&LOGI("Could not find end-of-central-directory in Zip\n");
& &&&* There are two interesting items in the EOCD block: the number of
& &&&* entries in the file, and the file offset of the start of the
& &&&* central directory.
& &&&* (There's actually a count of the #of entries in this file, and for
& &&&* all files which comprise a spanned archive, but for our purposes
& &&&* we're only interested in the current file.&&Besides, we expect the
& &&&* two to be equivalent for our stuff.)
& & numEntries = get2LE(ptr + kEOCDNumEntries);
& & cdOffset = get4LE(ptr + kEOCDFileOffset);
& & /* valid offsets are [0,EOCD] */
& & unsigned int maxO
& & maxOffset = (ptr - basePtr) +1;
& & LOGV("+++ numEntries=%d cdOffset=%d\n", numEntries, cdOffset);
& & if (numEntries == 0 || cdOffset &= length) {
& && &&&LOGW("Invalid entries=%d offset=%d (len=%zd)\n",
& && && && &numEntries, cdOffset, length);
& &&&* Create hash table.&&We have a minimum 75% load factor, possibly as
& &&&* low as 50% after we round off to a power of 2.
& & mNumEntries = numE
& & mHashTableSize = roundUpPower2(1 + ((numEntries * 4) / 3));
& & mHashTable = (HashEntry*) calloc(1, sizeof(HashEntry) * mHashTableSize);
& &&&* Walk through the central directory, adding entries to the hash
& &&&* table.
& & ptr = basePtr + cdO
& & for (i = 0; i & numE i++) {
& && &&&unsigned int fileNameLen, extraLen, commentLen, localHdrO
& && &&&const unsigned char* localH
& && &&&if (get4LE(ptr) != kCDESignature) {
& && && && &LOGW("Missed a central dir sig (at %d)\n", i);
& && && && &
& && &&&if (ptr + kCDELen & basePtr + length) {
& && && && &LOGW("Ran off the end (at %d)\n", i);
& && && && &
& && &&&localHdrOffset = get4LE(ptr + kCDELocalOffset);
& && &&&CHECK_OFFSET(localHdrOffset);
& && &&&fileNameLen = get2LE(ptr + kCDENameLen);
& && &&&extraLen = get2LE(ptr + kCDEExtraLen);
& && &&&commentLen = get2LE(ptr + kCDECommentLen);
& && &&&//LOGV("+++ %d: localHdr=%d fnl=%d el=%d cl=%d\n",
& && &&&//& & i, localHdrOffset, fileNameLen, extraLen, commentLen);
& && &&&//LOGV(" '%.*s'\n", fileNameLen, ptr + kCDELen);
& && &&&/* add the CDE filename to the hash table */
& && &&&hash = computeHash((const char*)ptr + kCDELen, fileNameLen);
& && &&&addToHash((const char*)ptr + kCDELen, fileNameLen, hash);
& && &//&&localHdr = basePtr + localHdrO
& && &//&&if (get4LE(localHdr) != kLFHSignature) {
& && && &&&// LOGW("Bad offset to local header: %d (at %d)\n",
& && && && & //& &localHdrOffset, i);
& && && & //&&
& &&&//& &}
& && &&&ptr += kCDELen + fileNameLen + extraLen + commentL
& && &&&CHECK_OFFSET(ptr - basePtr);
& & result =
#undef CHECK_OFFSET
& &&&红色部分是修改后的代码,大家可以对比一下。(未完。。。)
参考资料推荐:
& && && && &&
再传两个patch
阅读(345) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。}

我要回帖

更多关于 android 测试启动时间 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信