原文地址:http://m.blog.csdn.net/blog/yutou58nian/21176139
Android平臺上,一個App的啓動時間可以說是一個重要的性能指標。如何獲取一個App的啓動時間呢,接下來咱們詳細探討一下。
在查閱Android的文檔之後發現,Android的shell命令裏面是有這個功能的,打開adb,輸入以下命令
am是shell中集成的一個命令,ActivityManager的簡寫。一共需要提供兩個參數-W,-n,其中-W是指啓動完成之後,返回啓動耗時,是最關鍵的一個參數。-n後面跟的是需要啓動的App的包名和launchActivity。點擊確定之後,會發現App被成功啓動,且adb中會輸入以下結果
其中ThisTime即是本次App啓動所花費的時間。
到了這裏我們基本完成了一半的工作,但是每次都需要在adb中才能查看啓動時間無疑是很麻煩的,那麼如何在手機上通過一個App控制其他App的啓動,並獲取啓動時間呢,咱們繼續看。
首先通過shell看一下am命令中包含什麼,在System/bin目錄下面找到“am”命令,並打印出之後是如下的結果
可以看出他跟普通的shell命令不一樣,他是通過調用一個/framework/目錄下的一個am.jar完成的工作,並最終執行com.android.commands.am包下面的Am.java。那我們接下來要做的工作就是下載Android源碼,並找到這個Am.java。
Am.java部分代碼如下:
- public class Am extends BaseCommand {
- private IActivityManager mAm;
- ...
- public static void main(String[] args) {
- (new Am()).run(args);
- }
- ...
- @Override
- public void onRun() throws Exception {
- if (op.equals("start")) {
- runStart();
- }
- ...
- }
- private void runStart() throws Exception {
- ...
- IActivityManager.WaitResult result = null;
- int res;
- if (mWaitOption) {
- result = mAm.startActivityAndWait(null, null, intent, mimeType,
- null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
- res = result.result;
- } else {
- res = mAm.startActivityAsUser(null, null, intent, mimeType,
- null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
- }
- ...
- }
- }
看到代碼之後突然就有了一種豁然開朗的感覺,沒錯,就是main函數!他就是整個am命令的入口,並調用onRun方法。如果我們輸入的參數是“start"的話,會調用runStart()方法。在runStart()方法之前的預處理中,根據我們輸入的-W參數,將mWaitOption賦值爲true。然後最終就找到了整個命令的精髓所在--startActivityAndWait()!
到這一步之後,我們需要做的工作就是如何在自己的App中調用這個startActivityAndWait方法。
不過很明顯這個API是不對開發者開放的,Android系統中有很多隱藏API,Google之所以要將一些API隱藏(指加上@hide標記的public類、方法或常量)是因爲Android系統本身還在不斷的進化發展中。從1.0、1.1到現在4.4,這些隱藏的API本身可能是不穩定的(方法的參數數量,類型都會變化),所以使用隱藏API,意味着程序更差的兼容性。
但這並不意味着我們就不能使用它,這些隱藏的API在系統中都是真實存在的,只是不對外開放而已。我們可以通過三種方法調用它,分別是:JAVA反射機制、API欺騙、重新編譯Android源碼。
反射是Java的語言特性之一,在此不進行贅述,需要介紹一下API欺騙:燒製到手機中的android.jar包含了Android所需的各種類與方法;而供開發者使用的android.jar只是其中的一部分。API欺騙是指在應用中去模擬未公開的類和方法讓應用編譯通過並生成APK,然而在應用實際運行中調用的卻仍是燒製到手機中真實的android.jar。
通過查看源碼我們可以看到需要模擬的是ActivityManagerNative、IActivityManager和他的startActivityAndWait方法。參照源碼,實現以下代碼:
- package android.app;
- public abstract class ActivityManagerNative {
- public static IActivityManager getDefault() {
- return null;
- }
- }
- package android.app;
- import android.content.ComponentName;
- import android.os.Parcel;
- import android.os.Parcelable;
- public abstract interface IActivityManager {
- public WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo, String resultWho,
- int requestCode, int flags, String profileFile,
- ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException;
- public static class WaitResult implements Parcelable {
- public int result;
- public boolean timeout;
- public ComponentName who;
- public long thisTime;
- public long totalTime;
- };
- }
- package android.app;
- public abstract class ActivityManagerNative {
- public static IActivityManager getDefault() {
- return null;
- }
- }
- package android.app;
- import android.content.ComponentName;
- import android.os.Parcel;
- import android.os.Parcelable;
- public abstract interface IActivityManager {
- public static class WaitResult implements Parcelable {
- public int result;
- public boolean timeout;
- public ComponentName who;
- public long thisTime;
- public long totalTime;
- };
- }
- private void getStartActivityMethod() {
- activityManager = ActivityManagerNative.getDefault();
- Method[] methods = activityManager.getClass().getDeclaredMethods();
- for (int i = 0; i < methods.length; i++) {
- String methodName = methods[i].getName();
- if (methodName.contains("startActivityAndWait")) {
- startActivityMethod = methods[i];
- startActivityMethod.setAccessible(true);
- break;
- }
- }
- }
- // 4.4
- private long startActivityWithFieldsForApi19(Intent intent) {
- Object[] objects = new Object[] { null, null, intent, null, null, null, 0, 0, null, null, null, 0 };
- return startActivityForResult(objects);
- }
- private long startActivityForResult(Object[] objects) {
- try {
- Object object = startActivityMethod.invoke(activityManager, objects);
- WaitResult waitResult = (WaitResult) object;
- return waitResult.thisTime;
- } catch (IllegalArgumentException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return -1;
- }
個人整理的不同系統版本startActivityAndWait()函數的詳情:http://download.csdn.net/detail/yutou58nian/7049953