<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Android插件化的兼容性(中):Android P的適配

           Android系統(tǒng)的每次版本升級,都會對原有代碼進行重構(gòu),這就為插件化帶來了麻煩。

           Android P對插件化的影響,主要體現(xiàn)在兩方面,一是它重構(gòu)了H類中Activity相關(guān)的邏輯,另一個是它重構(gòu)了Instrumentation。

       

           3.1 H類的變身

           3.1.1 從Message和Handler說起

           對于App開發(fā)人員而言,Message和Handler是耳熟能詳?shù)膬蓚€概念。我們簡單回顧一下,一條消息是怎么發(fā)送和接收的。

           首先,在App啟動的時候,會創(chuàng)建ActivityThread,這就是主線程,也叫UI線程。App的入口——main函數(shù),就藏在ActivityThread中,

           在main函數(shù)中,會創(chuàng)建MainLooper。MainLooper是一個死循環(huán),專門負責接收消息,也就是Message類。

           Message類的定義如下,除了耳熟能詳?shù)膚hat和obj屬性外,還有一個不對App開放的變量target,它是一個Handler:

      public final class Message implements Parcelable {
          public int what;
          public Object obj;
           Handler target;
      
          //以下省略很多代碼哦
      }

       

           在App進程中,Application和四大組件的每個生命周期函數(shù),都要和AMS進程進行跨進程通信。

           1)App進程把數(shù)據(jù)傳給AMS進程,是通過ActivityManagerNative完成的。

           2)AMS進程把數(shù)據(jù)傳給App進程,App進程這邊接收數(shù)據(jù)的是ApplicationThread。

       

           ApplicationThread在接收到數(shù)據(jù)后,會調(diào)用sendMessage方法。這就把消息Message對象發(fā)送給了MainLooper這個死循環(huán)。

           在MainLooper死循環(huán)中,處理這個Message對象。怎么處理呢,取出它的target字段,這是一個Handler類型的對象,調(diào)用這個Handler對象的dispatchMessage方法。

           是時候看一下Handler類的結(jié)構(gòu)了,我簡化了它的代碼,為的是易于理解:

      public class Handler {
          final Callback mCallback;
      
          public interface Callback {
              public boolean handleMessage(Message msg);
          }
      
          public void handleMessage(Message msg) {
          }
          
          public void dispatchMessage(Message msg) {
              if (msg.callback != null) {
                  handleCallback(msg);
              } else {
                  if (mCallback != null) {
                      if (mCallback.handleMessage(msg)) {
                          return;
                      }
                  }
                  handleMessage(msg);
              }
          }
      }

       

           Handler類中有一個mCallback變量,這個變量是插件化技術(shù)的核心。書接上文,MainLooper調(diào)用了Handler的dispatchMessage方法,這個方法的邏輯是,要么執(zhí)行mCallback的handleMessage方法,要么執(zhí)行Handler類自己的handleMessage方法。

           Handler類自己的handleMessage方法,是一個空方法,所以我們一般寫一個Handler的子類,然后實現(xiàn)這個handleMessage方法。

           在Android系統(tǒng)底層,這個Handler類的子類,就是H類,我們在ActivityThread.java中可以找到這個類。H類的handleMessage方法中,定義了所有消息的分發(fā),如下所示:

      public final class ActivityThread {
          private class H extends Handler {
              public static final int LAUNCH_ACTIVITY         = 100;
              public static final int PAUSE_ACTIVITY           = 101;
              public static final int PAUSE_ACTIVITY_FINISHING= 102;
              public static final int STOP_ACTIVITY_SHOW      = 103;
              public static final int STOP_ACTIVITY_HIDE      = 104;
              public static final int SHOW_WINDOW             = 105;
              public static final int HIDE_WINDOW             = 106;
              public static final int RESUME_ACTIVITY         = 107;
              public static final int SEND_RESULT             = 108;
              public static final int DESTROY_ACTIVITY        = 109;
              public static final int BIND_APPLICATION        = 110;
              public static final int EXIT_APPLICATION        = 111;
              public static final int NEW_INTENT              = 112;
              public static final int RECEIVER                = 113;
      
              //以下省略很多代碼
      
              public void handleMessage(Message msg) {
                  switch (msg.what) {
                      case LAUNCH_ACTIVITY: {
                          final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
      
                          r.packageInfo = getPackageInfoNoCheck(
                                  r.activityInfo.applicationInfo, r.compatInfo);
                          handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                      } break;
                  
                  //以下省略很多代碼
                  }
              }
          }
      }

       

           在H類的handleMessage方法中,會根據(jù)msg參數(shù)的what值,來判斷到底是哪種消息,以及相應(yīng)的執(zhí)行什么邏輯,比如說,啟動Activity。

           在H類中,定義了幾十種消息,比如說LAUNCH_ACTIVITY的值是100,PAUSE_ACTIVITY的值是101。從100到109,都是給Activity的生命周期函數(shù)準備的。從110開始,才是給Application、Service、ContentProvider、BroadcastReceiver使用的。

           至此,我們簡單回顧了Android系統(tǒng)內(nèi)部Message的發(fā)送和接收流程。其中比較重要的是:

           1)Handler類中有一個mCallback變量。

           2)H類中定義了各種消息。

       

           3.1.2 Android P之前的插件化解決方案

           在Android P(API level 28)之前,我們做插件化,都是Hook掉H類的mCallback對象,攔截這個對象的handleMessage方法。在此之前,我們把插件中的Activity替換為StubActtivty,那么現(xiàn)在,我們攔截到handleMessage方法,再把StubActivity換回為插件中的Activity,代碼如下所示:

      class MockClass2 implements Handler.Callback {
      
          Handler mBase;
      
          public MockClass2(Handler base) {
              mBase = base;
          }
      
          @Override
          public boolean handleMessage(Message msg) {
      
              switch (msg.what) {
                  // ActivityThread里面 "LAUNCH_ACTIVITY" 這個字段的值是100
                  // 本來使用反射的方式獲取最好, 這里為了簡便直接使用硬編碼
                  case 100:
                      handleLaunchActivity(msg);
                      break;
              }
      
              mBase.handleMessage(msg);
              return true;
          }
      
          private void handleLaunchActivity(Message msg) {
              // 這里簡單起見,直接取出TargetActivity;
      
              Object obj = msg.obj;
      
              // 把替身恢復(fù)成真身
              Intent raw = (Intent) RefInvoke.getFieldObject(obj, "intent");
      
              Intent target = raw.getParcelableExtra(AMSHookHelper.EXTRA_TARGET_INTENT);
              raw.setComponent(target.getComponent());
          }
      }

       

           3.1.3 Android P對Activity消息機制的改造

           Android系統(tǒng)升級到P,它重構(gòu)了H類,把100到109這10個用于Activity的消息,都合并為159這個消息,消息名為EXECUTE_TRANSACTION。

           為什么要這么修改呢?相信大家面試Android工程師崗位的時候,都會被問及Activity的生命周期圖。這其實是一個由Create、Pause、Resume、Stop、Destory、Restart組成的狀態(tài)機。按照設(shè)計模式中狀態(tài)模式的定義,可以把每個狀態(tài)都定義成一個類,于是便有了如下的類圖:

       

       

           就拿LaunchActivity來說吧,在Android P之前,是在H類的handleMessage方法的switch分支語句中,編寫啟動一個Activity的邏輯:

              public void handleMessage(Message msg) {
                  switch (msg.what) {
                      case LAUNCH_ACTIVITY: {
                          final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
      
                          r.packageInfo = getPackageInfoNoCheck(
                                  r.activityInfo.applicationInfo, r.compatInfo);
                          handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                      } break;
                  
                  //以下省略很多代碼
                  }
              }

       

           在Android P中,啟動Activity的這部分邏輯,被轉(zhuǎn)移到了LaunchActivityItem類的execute方法中。

      public class LaunchActivityItem extends ClientTransactionItem {
      
          @Override
          public void execute(ClientTransactionHandler client, IBinder token,
                  PendingTransactionActions pendingActions) {
              ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                      mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                      mPendingResults, mPendingNewIntents, mIsForward,
                      mProfilerInfo, client);
              client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
          }
      }

       

           從架構(gòu)的角度來說,這次重構(gòu)的效果很好。使用狀態(tài)模式,使得Android這部分代碼,就是OOP的了。我們把寫在H類的handleMessage方法中的switch分支語句,拆分到很多類中,這就符合了五大設(shè)計原則中的開閉原則,寧肯有100個類,每個類有100行代碼,也不要有一個一萬行代碼的類。好處是,當我想改動Resume這個狀態(tài)的業(yè)務(wù)邏輯時,我只要在ResumeActivityItem類中修改并進行測試就可以了,影響的范圍很小。

           但是這次重構(gòu)也有缺點,OOP的缺點就是代碼會讓人看不懂,因為只有在運行時才知道到底實例化的是哪個類,這讓原本清晰的Android Activity消息邏輯變得支離破碎。

           按照這個趨勢,四大組件之一的Service,它在H類中也有很多消息,也是有很多生命周期函數(shù),Android的下個版本,極有可能把Service也重構(gòu)為狀態(tài)模式。

       

           3.1.4 Android P針對于H的Hook

           Android P把H類中的100-109這10個消息都刪除了,取而代之的是159這個消息,名為EXECUTE_TRANSACTION。

           這就導(dǎo)致我們之前的插件化解決方案,在Android P上是不生效的,會因為找不到100這個消息,而不能把StubActiivty換回為插件中的Activity。為此,我們需要攔截159這個消息。攔截后,我們又要面對如何判斷當前這個消息到底是Launch,還是Pause或者Resume。

           關(guān)鍵在于H類的handleMessage方法的Message參數(shù)。這個Message的obj字段,在Message是159的時候,返回的是ClientTransacion類型對象,它內(nèi)部有一個mActivityCallbacks集合:

      public class ClientTransaction implements Parcelable, ObjectPoolItem {
      
            private List<ClientTransactionItem> mActivityCallbacks;
      
      }

       

           這個mActivityCallbacks集合中,存放的是ClientTransactionItem的各種子類對象,比如LaunchActivityItem、DestoryActivityListItem。我們可以判斷這個集合中的值,發(fā)現(xiàn)有某個元素是LaunchActivityItem類型的,那么就相當于捕獲到了啟動Activity的那個消息。

           定位到LaunchActivityItem類的對象,它內(nèi)部有一個mIntent字段,里面存放的就是要啟動的Activity名稱,目前值是StubActivity。在這里把它替換為真正要啟動的插件Activity,代碼如下所示:

      class MockClass2 implements Handler.Callback {
      
          Handler mBase;
      
          public MockClass2(Handler base) {
              mBase = base;
          }
      
          @Override
          public boolean handleMessage(Message msg) {
      
              switch (msg.what) {
                  // ActivityThread里面 "LAUNCH_ACTIVITY" 這個字段的值是100
                  // 本來使用反射的方式獲取最好, 這里為了簡便直接使用硬編碼
                  case 100:   //for API 28以下
                      handleLaunchActivity(msg);
                      break;
                  case 159:   //for API 28
                      handleActivity(msg);
                      break;
              }
      
              mBase.handleMessage(msg);
              return true;
          }
      
          private void handleActivity(Message msg) {
              // 這里簡單起見,直接取出TargetActivity;
              Object obj = msg.obj;
      
              List<Object> mActivityCallbacks = (List<Object>) RefInvoke.getFieldObject(obj, "mActivityCallbacks");
              if(mActivityCallbacks.size() > 0) {
                  String className = "android.app.servertransaction.LaunchActivityItem";
                  if(mActivityCallbacks.get(0).getClass().getCanonicalName().equals(className)) {
                      Object object = mActivityCallbacks.get(0);
                      Intent intent = (Intent) RefInvoke.getFieldObject(object, "mIntent");
                      Intent target = intent.getParcelableExtra(AMSHookHelper.EXTRA_TARGET_INTENT);
                      intent.setComponent(target.getComponent());
                  }
              }
          }
      }

       

      3.2 Instrumentation的變身

           在Android P之前,Instrumentation的newActivity方法。邏輯如下:

          public Activity newActivity(ClassLoader cl, String className,
                  Intent intent)
                  throws InstantiationException, IllegalAccessException,
                  ClassNotFoundException {
              return (Activity)cl.loadClass(className).newInstance();
      }

       

           到了Android P,則改寫了Instrumentation類的部分邏輯。它會在newActivity方法中,檢查Instrumentation的mThread變量,如果為空,就會拋出一個異常:

      public class Instrumentation {
          public Activity newActivity(ClassLoader cl, String className,
                  Intent intent)
                  throws InstantiationException, IllegalAccessException,
                  ClassNotFoundException {
              String pkg = intent != null && intent.getComponent() != null
                      ? intent.getComponent().getPackageName() : null;
              return getFactory(pkg).instantiateActivity(cl, className, intent);
          }
      
          private AppComponentFactory getFactory(String pkg) {
              if (pkg == null) {
                  Log.e(TAG, "No pkg specified, disabling AppComponentFactory");
                  return AppComponentFactory.DEFAULT;
              }
              if (mThread == null) {
                  Log.e(TAG, "Uninitialized ActivityThread, likely app-created Instrumentation,"
                          + " disabling AppComponentFactory", new Throwable());
                  return AppComponentFactory.DEFAULT;
              }
              LoadedApk apk = mThread.peekPackageInfo(pkg, true);
              // This is in the case of starting up "android".
              if (apk == null) apk = mThread.getSystemContext().mPackageInfo;
              return apk.getAppFactory();
          }
      }

       

           我們在本書第5章介紹給一種Hook方案,攔截Instrumentation類的execStartActivity方法,如下所示:

      public class HookHelper {
      
          public static void attachContext() throws Exception{
              // 先獲取到當前的ActivityThread對象
              Object currentActivityThread = RefInvoke.invokeStaticMethod("android.app.ActivityThread", "currentActivityThread");
      
              // 拿到原始的 mInstrumentation字段
              Instrumentation mInstrumentation = (Instrumentation) RefInvoke.getFieldObject(currentActivityThread, "mInstrumentation");
      
              // 創(chuàng)建代理對象
              Instrumentation evilInstrumentation = new EvilInstrumentation(mInstrumentation);
      
              // 偷梁換柱
              RefInvoke.setFieldObject(currentActivityThread, "mInstrumentation", evilInstrumentation);
          }
      }
      
      public class EvilInstrumentation extends Instrumentation {
      
          private static final String TAG = "EvilInstrumentation";
      
          // ActivityThread中原始的對象, 保存起來
          Instrumentation mBase;
      
          public EvilInstrumentation(Instrumentation base) {
              mBase = base;
          }
      
          public ActivityResult execStartActivity(
                  Context who, IBinder contextThread, IBinder token, Activity target,
                  Intent intent, int requestCode, Bundle options) {
      
              Log.d(TAG, "XXX到此一游!");
      
              // 開始調(diào)用原始的方法, 調(diào)不調(diào)用隨你,但是不調(diào)用的話, 所有的startActivity都失效了.
              // 由于這個方法是隱藏的,因此需要使用反射調(diào)用;首先找到這個方法
              Class[] p1 = {Context.class, IBinder.class,
                      IBinder.class, Activity.class,
                      Intent.class, int.class, Bundle.class};
              Object[] v1 = {who, contextThread, token, target,
                      intent, requestCode, options};
      
              return (ActivityResult) RefInvoke.invokeInstanceMethod(
                      mBase, "execStartActivity", p1, v1);
          }
      }

       

           這段代碼,我們把系統(tǒng)原先的Instrumentation替換成EvilInstrumentation,在Android P以下的系統(tǒng)是可以運行的,但是在Android P上就會拋出Uninitialized ActivityThread, likely app-created Instrumentation的異常,顯然這是因為EvilInstrumentation的mThread為空導(dǎo)致的。

           想要解決這個問題,就必須重寫EvilInstrumentation中的newActivity方法,如下所示:

      public class EvilInstrumentation extends Instrumentation {
          //省略了部分代碼
      
          public Activity newActivity(ClassLoader cl, String className,
                                      Intent intent)
                  throws InstantiationException, IllegalAccessException,
                  ClassNotFoundException {
      
              return mBase.newActivity(cl, className, intent);
          }
      }

       

           這樣編碼,即使是EvilInstrumentation,在執(zhí)行newActivity方法的時候,也會執(zhí)行原先Instrumentation的newActivity方法,Instrumentation的mThread字段不是null,所以就不會拋出上述的異常信息了。

      posted @ 2018-08-23 00:29  包建強  Views(14302)  Comments(1)    收藏  舉報
      主站蜘蛛池模板: 久久天天躁夜夜躁狠狠85| 亚洲真人无码永久在线| 九九热在线这里只有精品| 欧美日韩一区二区三区视频播放| 鲁丝片一区二区三区免费| 久久人人97超碰精品| 中文字幕久久久久人妻| 国产亚洲精品第一综合| 国产精品一区二区日韩精品| 亚洲天堂激情av在线| 久久精品中文字幕免费| 日韩精品一区二区三区激| 国产高清av首播原创麻豆| 香蕉久久久久久久AV网站| 四川丰满少妇无套内谢| 国产一级特黄高清大片一| 影音先锋啪啪av资源网站| 国产99视频精品免费观看9| 国产一区二区三区AV在线无码观看| 亚洲第一狼人天堂网伊人| 久久毛片少妇高潮| 人妻中文字幕不卡精品| 宝贝腿开大点我添添公视频免 | 亚洲成人av在线系列| 国产拗精品一区二区三区| 久久国产免费观看精品3| 国产成人免费永久在线平台| 中文字幕国产精品自拍| 99er热精品视频| 久久中文字幕日韩无码视频| 亚洲精品人成网线在线播放va | 丁香婷婷在线视频| 亚洲人成网线在线播放VA | 99久久er热在这里只有精品99| 亚洲国产成人久久精品不卡 | 国产精品自在拍在线播放| 亚洲AV成人片不卡无码| 亚洲色一色噜一噜噜噜| 亚洲天堂领先自拍视频网| 99久久久国产精品免费无卡顿| 国产一级精品在线免费看|