国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Android攔截AMS請求實戰

移動開發
下面從各個 Android 版本看一下系統這個過程的實現方法以及我們是怎么攔截的,主要看一下 Android P 的源碼,其它版本的雖然過程不一樣,但是 Hook 的方式是類似的。

概述

接著上次后臺啟動 Activity 的需求,依照 實戰|Android后臺啟動Activity實踐之路 中的一些方法處理后,雖然在 Android Q 版本上還是有一些問題,但后臺啟動的能力算是基本完成了,后來我又解開了小米 ROM 的源碼,找到了他們后臺啟動這一項權限的實現方式以及怎么繞開這項權限的方法,發現結果意外的簡單..(這部分以后有機會單獨寫一篇文章)。

[[377520]]

這篇文章發生在后臺啟動的調研之后,如果我們要后臺啟動的 Activity 頁面在第三方 SDK 里,且啟動該頁面的動作(startActivity)也發生在第三方 SDK 中,那么它們直接 startActivity 的方式是不具備后臺啟動的能力的,因為一些原因我們不能要求 SDK 方修改啟動 Activity 的方法,因此需要找個方法能夠在不修改第三方 SDK 調用 startActivity 代碼的情況下,讓其具備后臺啟動的能力。第一個反應就是攔截 startActivity 的請求,參考 Android之system_server進程 和 Android-Activity啟動流程,我們知道 AMS 是 system_server 進程中的一個線程,它負責啟動 Activity 的具體工作,在它的工作完成之后,會通過 Binder 調用回調 APP 進程中 Activity 實例的生命周期方法。當 APP 進程調用 startActivity 時,會由 Instrumentation 獲取到 AMS 的 Binder 代理,然后通過它來跨進程調用 AMS 的相關方法,我們能做 Hook 攔截的地方就是這個 Binder 代理對象!

下面從各個 Android 版本看一下系統這個過程的實現方法以及我們是怎么攔截的,主要看一下 Android P 的源碼,其它版本的雖然過程不一樣,但是 Hook 的方式是類似的。

Android P

Android 8 到 Android 9 版本的 AOSP 獲取 AMS 代理的方式是一樣的,APP 進程在調用 context.startActivity 后,會來到 Instrumentation 中的相關方法里調用如下代碼:

  1. int result = ActivityManager.getService().startActivity(whoThread, who.getBasePackageName(), intent, ...); 

這里通過 Binder 跨進程調用到 AMS 中的相關方法,看一下 ActivityManager.getService() 的實現:

 

  1. /** @hide */ 
  2. public static IActivityManager getService() { 
  3.     return IActivityManagerSingleton.get(); 
  4.  
  5. private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() { 
  6.      
  7.  
  8.  
  9.     protected IActivityManager create() { 
  10.         // 1... 
  11.     } 
  12. }; 

可以看到 IActivityManagerSingleton 是 Singleton 類型的實例,很顯然這個 Singleton 是一個懶加載的單例模板類:

  1. public abstract class Singleton<T> { 
  2.     private T mInstance; 
  3.  
  4.     protected abstract T create(); 
  5.  
  6.     public final T get() { 
  7.         synchronized (this) { 
  8.             if (mInstance == null) { 
  9.                 mInstance = create(); 
  10.             } 
  11.             return mInstance; 
  12.         } 
  13.     } 

于是可以知道 IActivityManagerSingleton.get() 返回的便是 create 方法中的實例,給出上面 1 處省略的 create 方法代碼:

  1. final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); 
  2. final IActivityManager am = IActivityManager.Stub.asInterface(b); 
  3. return am; 

熟悉 Binder 的同學一眼就能看出這里的 am 是一個 Binder 代理對象,存在 ServiceManager.getService 方法就肯定存在 ServiceManager.addService 方法,一個是從 ServiceManager 中查詢 Binder 服務,一個是往 ServiceManager 中注冊服務,注冊的時機在系統啟動 system_server 進程的時候,參考 AMS啟動流程,這里就不深入描述了。

所以 ActivityManager.getService() 方法其實就是返回了 AMS 的一個 Binder 代理對象,用來跨進程調用 AMS 相關方法,因此可以通過 JDK 動態代理的方式,通過 Proxy.newProxyInstance 方法創建 am 的代理 Proxy 對象,并通過反射的方式將 ActivityManager.getService() 方法返回的 am 對象替換成我們的 Proxy 對象,那么在 App 進程調用 ActivityManager.getService().XXX 方法時都會被我們的 Proxy 攔截到,進而做一些處理。JDK 動態代理也是 Java 常用的設計模式之一,不太熟悉的同學可以參考 Jdk動態代理 的使用。

這個過程可以分成三個步驟:

  1. 反射獲取 am 對象,由于 ActivityManager.getService() 是一個隱藏方法,因此可以通過反射調用它拿到原 am 對象;
  2. 創建代理對象Proxy;
  3. 通過反射用 Proxy 替換 am 對象;

我們看到 am 對象其實就是 Singleton(其實例是IActivityManagerSingleton) 中的 mInstance 屬性,因此第三步只需通過反射將 mInstance 屬性設置為我們的 Proxy 對象即可,下面的 AmsHooker 是一個抽象類,在不同的 Android 平臺上有不同的實現,主要用來獲取不同 Android 平臺的 am 對象及通過反射替換 am 對象:

  1. abstract class AmsHooker { 
  2.     // 通過反射,將am替換成proxy 
  3.     fun hookAms(proxy: Any?) { 
  4.         try { 
  5.             val hookObj = getHookObj() 
  6.             val hookField = getHookField() 
  7.             if (hookObj != null && hookField != null && proxy != null) { 
  8.                 hookField.set(hookObj, proxy) 
  9.             } 
  10.         } catch (e: Exception) { 
  11.             e.printStackTrace() 
  12.         } 
  13.     } 
  14.  
  15.     // 即IActivityManagerSingleton實例 
  16.     protected abstract fun getHookObj(): Any
  17.  
  18.     // 即mInstance 
  19.     protected abstract fun getHookField(): Field? 
  20.  
  21.     // 即am 
  22.     abstract fun getTarget(): Any
  23.  
  24.     // 接口,用來創建Proxy 
  25.     abstract fun getInterfaces(): Array<Class<*>> 

在 Android P 平臺上的實現如下,具體看注釋:

  1. class AmsPHooker : AmsHooker() { 
  2.     override fun getHookObj(): Any? { 
  3.         val amClass = ReflectUtils.getClass("android.app.ActivityManager"
  4.         // 拿到 IActivityManagerSingleton 屬性 
  5.         return ReflectUtils.readStaticField(amClass, "IActivityManagerSingleton"
  6.     } 
  7.  
  8.     override fun getHookField(): Field? { 
  9.         // 獲取 mInstance Field 
  10.         return ReflectUtils.getField(ReflectUtils.getClass("android.util.Singleton"), "mInstance"
  11.     } 
  12.  
  13.     override fun getTarget(): Any? { 
  14.         // ActivityManager.getService()返回 am 
  15.         return ReflectUtils.getClass("android.app.ActivityManager").getDeclaredMethod("getService").invoke(null
  16.     } 
  17.  
  18.     // 獲取interfaces,用來創建動態代理 
  19.     override fun getInterfaces(): Array<Class<*>> { 
  20.         return arrayOf(ReflectUtils.getClass("android.app.IActivityManager")) 
  21.     } 

接下來創建代理類(代碼有刪減):

 

  1. public class AMSProxy implements InvocationHandler { 
  2.     private AmsHooker hooker; // 根據不同 Android 平臺返回不同實現 
  3.     private Object origAm; // 原有 am 對象 
  4.  
  5.     private boolean ensureInit() { 
  6.         // ... 
  7.         hooker = getHooker(); 
  8.         origAm = hooker.getTarget(); 
  9.     } 
  10.  
  11.     private AmsHooker getHooker() { 
  12.         if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { 
  13.             return new AmsQHooker(); 
  14.         } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) { 
  15.             return new AmsPHooker(); 
  16.         } else { 
  17.             return new AmsNHooker(); 
  18.         } 
  19.     } 
  20.  
  21.      
  22.  
  23.  
  24.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  25.         // ... 
  26.     } 
  27.  
  28.     // 創建代理 
  29.     Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), 
  30.                 hooker.getInterfaces(), this); 
  31.     // 替換系統am對象 
  32.     hooker.hookAms(proxy); 

上面以 AMSProxy 實例為參數創建了一個代理對象 Proxy,并用這個 Proxy 對象通過 hookAms 方法替換掉了 am 對象,這樣在本進程通過 ActivityManager.getService() 來調用相關方法時,會調用到上述的 invoke 方法,在這可以做攔截:

  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  2.     try { 
  3.         if (callback.canIntercept(method, args)) { 
  4.             if (callback.autoRemove()) { 
  5.                 // 將am對象還原 
  6.                 // ... 
  7.             } 
  8.             // 攔截am的請求,做自己的業務處理 
  9.             return callback.intercept(origAm, method, args); 
  10.         } 
  11.         return method.invoke(origAm, args); 
  12.     } catch (Exception e) { 
  13.         e.printStackTrace(); 
  14.     } 
  15.     return null

當本進程中有代碼嘗試通過 am 來調用相關方法(比如說startActivity等)時,都會被 invoke 方法所攔截,然后通過我們設置的攔截條件(canIntercept)去選擇是否攔截。建議每次完成了攔截的業務需求后,就把原 am 對象通過 hookAms 方法還原,防止的本次進程中持續攔截系統請求。這里一直強調是本次進程,顯而易見,通過反射去替換 am 對象的方式,只會針對本進程起作用。

Android Q

在 Android Q 上,上述 Instrumentation 中的調用變成如下:

  1. int result = ActivityTaskManager.getService().startActivity(whoThread, who.getBasePackageName(), intent, ...); 

這變成了 ActivityTaskManager.getService():

 

  1. /** @hide */ 
  2. public static IActivityTaskManager getService() { 
  3.     return IActivityTaskManagerSingleton.get(); 
  4.  
  5. private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton = new Singleton<IActivityTaskManager>() { 
  6.      
  7.  
  8.  
  9.     protected IActivityTaskManager create() { 
  10.         final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE); 
  11.         return IActivityTaskManager.Stub.asInterface(b); 
  12.     } 
  13. }; 

可以看到在 Android Q 上從 ActivityManager 變成了 ActivityTaskManager 系列的類,于是我們的 AmsQHooker 實現如下:

  1. class AmsQHooker : AmsHooker() { 
  2.     override fun getHookObj(): Any? { 
  3.         val amClass = ReflectUtils.getClass("android.app.ActivityTaskManager"
  4.         // 拿到 IActivityTaskManagerSingleton 屬性 
  5.         return ReflectUtils.readStaticField(amClass, "IActivityTaskManagerSingleton"
  6.     } 
  7.  
  8.     override fun getHookField(): Field? { 
  9.         return ReflectUtils.getField(ReflectUtils.getClass("android.util.Singleton"), "mInstance"
  10.     } 
  11.  
  12.     override fun getTarget(): Any? { 
  13.         // Reflective access to getService is forbidden when targeting API 29 and above 
  14.         // val getServiceMethod = amClass.getDeclaredMethod("getService"
  15.         return ReflectUtils.getClass("android.util.Singleton").getDeclaredMethod("get").invoke(getHookObj()) 
  16.     } 
  17.  
  18.     override fun getInterfaces(): Array<Class<*>> { 
  19.         return arrayOf(ReflectUtils.getClass("android.app.IActivityTaskManager")) 
  20.     } 

其它的步驟跟 Android P 是一樣的。

Android N

在 Android 7.1 及以下,Instrumentation 的調用又不一樣:

  1. int result = ActivityManagerNative.getDefault().startActivity(whoThread, who.getBasePackageName(), intent, ...); 

這變成了 ActivityManagerNative.getDefault():

  1. static public IActivityManager getDefault() { 
  2.     return gDefault.get(); 
  3.  
  4. private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { 
  5.     protected IActivityManager create() { 
  6.         IBinder b = ServiceManager.getService("activity"); 
  7.         IActivityManager am = asInterface(b); 
  8.         return am; 
  9.     } 
  10. }; 

可以看到雖然類名和方法有所變化,但還是借助了 Singleton 類,所以只需要繼承 AmsHooker 重寫相關方法即可:

  1. class AmsNHooker : AmsHooker() { 
  2.     override fun getHookObj(): Any? { 
  3.         val amNativeClass = ReflectUtils.getClass("android.app.ActivityManagerNative"
  4.         // 獲取gDefault實例 
  5.         return ReflectUtils.readStaticField(amNativeClass, "gDefault"
  6.     } 
  7.  
  8.     override fun getHookField(): Field? { 
  9.         return ReflectUtils.getField(ReflectUtils.getClass("android.util.Singleton"), "mInstance"
  10.     } 
  11.  
  12.     override fun getTarget(): Any? { 
  13.         return getHookField()?.get(getHookObj()) 
  14.     } 
  15.  
  16.     override fun getInterfaces(): Array<Class<*>> { 
  17.         return arrayOf(ReflectUtils.getClass("android.app.IActivityManager")) 
  18.     } 

其它的也是重用 Android P 上的邏輯。

總結

通過上面的方式,可以實現 在本進程內攔截通過 AMS 的 Binder 代理調用的相關方法,可以用來實現一些非常規的功能,雖然最近做的需求都比較非常規(liumang),不過拋開需求,對于開發而言去調研這些技術,還是挺有意思的..哈~

寫博客是一件有意思有收獲也有難度的事情,需要爭取把文章的脈絡和邏輯梳理清楚,怎么寫才能把文章寫得更加清晰易懂,又有好久沒更新了,最近太忙了都沒有時間做這些事情,想到自己寫的文章(可)能被點贊,瞬間又有了動力,于是忙里偷魚寫了一篇,內容沒啥深度,就當平時的開發筆記吧。

責任編輯:未麗燕 來源: 蒼耳的微博
相關推薦

2021-10-28 09:36:12

高并發數據實踐

2024-08-05 09:29:00

前端接口請求

2021-10-29 16:36:53

AMSAndroidActivityMan

2021-01-12 08:20:51

AndroidActivity系統

2019-03-01 09:55:28

HTTPMock架構

2012-07-20 11:13:07

云計算

2021-03-27 22:21:48

HTTPPython數據

2025-04-18 10:26:29

后端接口通用封裝

2024-05-20 08:21:36

Activity內部類接口

2012-02-03 09:14:44

谷歌惡意應用Android

2024-09-02 08:17:18

2021-03-26 06:01:45

日志MongoDB存儲

2012-11-08 20:39:18

2024-05-13 09:32:06

攔截器HTTP中間件

2012-04-26 10:50:37

2012-04-11 09:51:50

2015-05-15 11:25:53

2012-02-20 13:44:08

2020-11-12 09:55:02

OAuth2

2021-02-25 15:14:16

.NET項目攔截器
點贊
收藏

51CTO技術棧公眾號

在线黄色国产电影| 欧美午夜www高清视频| 激情综合婷婷| 国产日韩精品一区二区三区| 亚洲国产99精品国自产| 国产在线高清| 91久久中文字幕| 精品高清一区二区三区| 久久一区二区三区电影| 第一视频专区在线| 人人妻人人添人人爽欧美一区| 成人疯狂猛交xxx| 亚洲激情在线播放| 91.成人天堂一区| 亚洲午夜电影在线观看| 青草在线视频在线观看| 日韩一区二区三区免费| 美乳视频一区二区| 99国产欧美另类久久久精品| 宅男噜噜噜66国产精品免费| 激情小说 在线视频| 一区二区免费在线观看| 色偷偷噜噜噜亚洲男人的天堂| 激情av综合| 日韩av高清在线播放| 日本成人激情视频| 精品亚洲一区二区三区| 日韩欧美一卡二卡| 亚洲一区二区黄色| 久久影院视频免费| 韩国三级电影一区二区| 国产精品综合av一区二区国产馆| 久久精品magnetxturnbtih| 欧美日韩激情在线| 欧美精品黑人性xxxx| 欧美性xxxx极品hd欧美风情| 99久久精品免费精品国产| 最近中文字幕一区二区三区| 亚洲国产综合人成综合网站| 欧美情侣在线播放| 久久精品30| 大乳在线免费观看| 黄www在线观看| 妞干网在线播放| 亚洲一级淫片| 精品大片一区二区| 国产精品99一区二区三| 日本黄色精品| 先锋资源久久| 狠狠狠色丁香婷婷综合久久五月| 三级欧美韩日大片在线看| 欧美日韩视频在线| 国产亚洲精品一区二区| 欧美变态tickling挠脚心| 国产精品久久网站| 亚洲一区在线电影| 欧洲视频一区二区| 久久久精品美女| 91另类视频| 亚洲色图美腿丝袜| 一区二区三区四区激情| 亚洲成年人影院| 欧美一区二区三区色| 亚洲人成在线一二| 77777亚洲午夜久久多人| 91久久国产自产拍夜夜嗨| 欧美一区免费视频| 超碰影院在线观看| 欧美变态视频| 自拍偷自拍亚洲精品被多人伦好爽 | 国产精品久久久久久久av电影| 久久精品成人一区二区三区蜜臀| 久久久天堂国产精品| 日韩偷拍自拍| 亚洲免费看片| 青青青爽久久午夜综合久久午夜| 最新热久久免费视频| 亚洲第一精品夜夜躁人人躁| 欧美主播福利视频| 中文字幕第一页亚洲| 午夜黄色在线观看| 久久久久97| 粉嫩嫩av羞羞动漫久久久| 欧美午夜精品理论片a级按摩| 欧美大片免费看| 中文字幕在线亚洲三区| 毛片在线播放网址| 亚洲精品无吗| 国产风韵犹存在线视精品| 日韩美女在线视频| 国产精品波多野结衣| 亚洲国产91视频| 日本成人黄色网址| 国产黄色片大全| 国产日韩一区欧美| 欧美精品一区二区免费| 亚洲综合中文字幕68页| 91成人综合网| 毛片视频免费| 欧美另类tv| 久久不卡日韩美女| 国产在线观看a视频| 欧美孕妇孕交xxⅹ孕妇交| 欧美男女交配| 美日韩一区二区| 五月婷婷色综合| 日韩精品亚洲一区二区三区免费| 一本久久a久久精品亚洲| 欧美裸体网站| 在线视频国产区| 影音先锋一区| 污色网站在线观看| 亚洲一区二区三区四区中文| 精品少妇一区二区三区 | 亚洲.欧美.日本.国产综合在线| 亚洲欧美久久久| 福利视频网站| 中文字幕日韩精品一区| 一区二区三区高清视频在线观看| 国产日韩精品视频一区| 麻豆一区在线| 日韩精品欧美激情一区二区| 一级女性全黄久久生活片免费| 国语自产精品视频在线看一大j8 | 日日骚一区二区网站| av中文字幕在线看| 麻豆精品一区二区综合av| 中文字幕在线日韩| 久草免费在线播放| 国产精品最新自拍| 精品福利av导航| jizz欧美激情18| 亚洲综合色站| 欧美精品一区二区久久婷婷| 91久久在线| 日韩成人在线视频| 中文字幕免费在线视频| 亚洲福利精品| 成人久久视频在线观看| 91精品国产九九九久久久亚洲| www.日日操| 一区精品久久| 国产性猛交xxxx免费看久久| 成人在线观看黄| 色喇叭免费久久综合网| 日韩av资源在线播放| 欧美在线观看视频网站| 日韩激情中文字幕| 欧美中文字幕视频| 中文字幕这里只有精品| 亚洲欧洲av色图| 一区二区91美女张开腿让人桶| 九九视频免费观看视频精品| 一区二区三区在线观看国产| 日韩免费三级| 久久国产精品美女| 日韩精品在线观看一区二区| 激情五月亚洲色图| 亚洲色图18p| 日本精品免费在线观看| 久久国产精品美女| 亚洲va国产天堂va久久en| 成人在线看片| 精品午夜视频| 欧美一区三区二区| 日韩视频在线免费看| 1024精品久久久久久久久| 性日韩欧美在线视频| av手机在线观看| 亚洲不卡av一区二区三区| 欧美下载看逼逼| 亚洲一区 二区 三区| 色偷偷888欧美精品久久久| 你懂的在线网址| caoporn国产精品| 91在线精品观看| 无码国模国产在线观看| 亚洲成人精品在线| 菠萝菠萝蜜在线视频免费观看 | 欧美黄色一区二区| 米奇精品一区二区三区在线观看| wwww亚洲| 亚洲国产精品va在看黑人| 精品美女在线观看视频在线观看| 91精品一区| 国产精品美女久久久久久久久 | 69视频在线播放| 国产成人精品123区免费视频| 在线成人小视频| 国产精品剧情一区二区在线观看| 午夜精品久久久久久久99水蜜桃| 开心丁香婷婷深爱五月 | 蜜臀av一区| 欧美日韩xxx| 国产三级一区| 亚洲第一网站免费视频| 国产一二在线播放| 欧美xingq一区二区| 中文日本在线观看| 这里只有精品99re|