Android 插件化系列文章目录

【Android 插件化】插件化简介 ( 组件化与插件化 )
【Android 插件化】插件化原理 ( JVM 内存数据 | 类加载流程 )
【Android 插件化】插件化原理 ( 类加载器 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 注入上下文的使用 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 获取插件入口 Activity 组件 | 加载插件 Resources 资源 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 运行应用 | 代码整理 )

【Android 插件化】Hook 插件化框架 ( Hook 技术 | 代理模式 | 静态代理 | 动态代理 )
【Android 插件化】Hook 插件化框架 ( Hook 实现思路 | Hook 按钮点击事件 )
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动过程 | 静态代理 )


文章目录

  • Android 插件化系列文章目录
  • 前言
  • 一、分析 Activity 启动源码
    • 1、源码分析
    • 2、涉及到的 Activity 相关代码
  • 二、Hook Activity 启动过程
    • 1、分析相关 类 / 成员 / 方法 结构
    • 2、反射获取 Activity 中的 Instrumentation mInstrumentation 成员字段
    • 3、获取 Activity 中的 Instrumentation mInstrumentation 成员字段值
    • 4、设置 Activity 中的 Instrumentation mInstrumentation 成员字段值
    • 5、代理类开发
  • 三、完整代码示例
    • 1、主界面代码示例
    • 2、代理类代码示例
    • 3、跳转的界面
    • 4、执行结果
  • 四、博客资源

前言

上一篇博客 【Android 插件化】Hook 插件化框架 ( Hook 实现思路 | Hook 按钮点击事件 ) 简要介绍了 Hook 实现思路 , 以及使用静态代理实现了 Hook 按钮点击事件 ;

在本博客中使用 Hook 技术进行 Hook 住 Activity 启动过程 ;


一、分析 Activity 启动源码


1、源码分析

在 " 宿主 " 模块中 , 启动 " 插件 " 模块 , 调用的是 startActivity 方法 ;

如果要 Hook Activity 的启动过程 , 必须熟悉启动 Activity 的源码 , 下面开始分析 调用 startActivity 方法的源码逻辑 ;

在 Activity 中启动另外一个 Activity , 调用 void startActivity(Intent intent) 方法 ,

    @Overridepublic void startActivity(Intent intent) {this.startActivity(intent, null);}

在该 void startActivity(Intent intent) 方法中主要调用 void startActivity(Intent intent, @Nullable Bundle options) 重载方法 ;

    @Overridepublic void startActivity(Intent intent, @Nullable Bundle options) {if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)&& mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {if (TextUtils.equals(getPackageName(),intent.resolveActivity(getPackageManager()).getPackageName())) {// Apply Autofill restore mechanism on the started activity by startActivity()final IBinder token =mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);// Remove restore ability from current activitymIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);// Put restore tokenintent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);}}if (options != null) {startActivityForResult(intent, -1, options);} else {// Note we want to go through this call for compatibility with// applications that may have overridden the method.startActivityForResult(intent, -1);}}

在 void startActivity(Intent intent, @Nullable Bundle options) 中 , 最终调用了 void startActivityForResult(@RequiresPermission Intent intent, int requestCode) 方法 启动 Activity ;

void startActivityForResult(@RequiresPermission Intent intent, int requestCode) 方法最终也是调用 void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) 重载方法 , 最后一个参数设置为 null ;

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {startActivityForResult(intent, requestCode, null);}public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {if (mParent == null) {options = transferSpringboardActivityOptions(options);Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);if (ar != null) {mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(),ar.getResultData());}if (requestCode >= 0) {// If this start is requesting a result, we can avoid making// the activity visible until the result is received.  Setting// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the// activity hidden during this time, to avoid flickering.// This can only be done when a result is requested because// that guarantees we will get information back when the// activity is finished, no matter what happens to it.mStartedActivity = true;}cancelInputsAndStartExitTransition(options);// TODO Consider clearing/flushing other event sources and events for child windows.} else {if (options != null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {// Note we want to go through this method for compatibility with// existing applications that may have overridden it.mParent.startActivityFromChild(this, intent, requestCode);}}}

在 void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) 方法中 , 调用了 Instrumentation mInstrumentation 成员的 execStartActivity 方法 , 启动 Activity ;

            Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);

通过 Hook 该 execStartActivity 方法 , 使用该方法启动的 Activity 有完整的上下文环境 ;

2、涉及到的 Activity 相关代码

Activity 相关完整代码 :

public class Activity extends ContextThemeWrapperimplements LayoutInflater.Factory2,Window.Callback, KeyEvent.Callback,OnCreateContextMenuListener, ComponentCallbacks2,Window.OnWindowDismissedCallback,AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {@Overridepublic void startActivity(Intent intent) {this.startActivity(intent, null);}@Overridepublic void startActivity(Intent intent, @Nullable Bundle options) {if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)&& mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {if (TextUtils.equals(getPackageName(),intent.resolveActivity(getPackageManager()).getPackageName())) {// Apply Autofill restore mechanism on the started activity by startActivity()final IBinder token =mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);// Remove restore ability from current activitymIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);// Put restore tokenintent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);}}if (options != null) {startActivityForResult(intent, -1, options);} else {// Note we want to go through this call for compatibility with// applications that may have overridden the method.startActivityForResult(intent, -1);}}public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {startActivityForResult(intent, requestCode, null);}public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {if (mParent == null) {options = transferSpringboardActivityOptions(options);Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);if (ar != null) {mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(),ar.getResultData());}if (requestCode >= 0) {// If this start is requesting a result, we can avoid making// the activity visible until the result is received.  Setting// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the// activity hidden during this time, to avoid flickering.// This can only be done when a result is requested because// that guarantees we will get information back when the// activity is finished, no matter what happens to it.mStartedActivity = true;}cancelInputsAndStartExitTransition(options);// TODO Consider clearing/flushing other event sources and events for child windows.} else {if (options != null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {// Note we want to go through this method for compatibility with// existing applications that may have overridden it.mParent.startActivityFromChild(this, intent, requestCode);}}}
}

二、Hook Activity 启动过程


1、分析相关 类 / 成员 / 方法 结构

要 Hook 的方法是 Instrumentation 的 execStartActivity 方法 ;

public class Instrumentation {@UnsupportedAppUsagepublic ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {}
}

Activity 中维护了 Instrumentation mInstrumentation 成员变量 ;

public class Activity extends ContextThemeWrapperimplements LayoutInflater.Factory2,Window.Callback, KeyEvent.Callback,OnCreateContextMenuListener, ComponentCallbacks2,Window.OnWindowDismissedCallback,AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {// set by the thread after the constructor and before onCreate(Bundle savedInstanceState) is called.@UnsupportedAppUsageprivate Instrumentation mInstrumentation;
}

2、反射获取 Activity 中的 Instrumentation mInstrumentation 成员字段

首先 , 任何反射操作 , 都要获取其字节码文件 , 作为反射的入口 , 这里先获取 Activity 字节码对象 , 直接通过 Activity.class 获取即可 ;

        // 1. 获取 Activity 字节码文件//    字节码文件是所有反射操作的入口Class<?> clazz = Activity.class;

然后 , 获取 Activity 中的 Instrumentation mInstrumentation 成员 Field 字段 ;

        // 2. 获取 Activity 的 Instrumentation mInstrumentation 成员 Field 字段Field mInstrumentation_Field = null;try {mInstrumentation_Field = clazz.getDeclaredField("mInstrumentation");} catch (NoSuchFieldException e) {e.printStackTrace();}

最后 , 设置 Field mInstrumentation 字段的可访问性 , 只要是调用反射方法 , 或者访问反射的成员字段 , 第一件事就是设置可访问性 ;

正常可访问的方法或字段 , 绝对不会使用反射获取 , 既然使用了反射 , 那么设置可访问性是标配操作 ;

        // 3. 设置 Field mInstrumentation 字段的可访问性mInstrumentation_Field.setAccessible(true);

本步骤完整代码示例 :

        // 1. 获取 Activity 字节码文件//    字节码文件是所有反射操作的入口Class<?> clazz = Activity.class;// 2. 获取 Activity 的 Instrumentation mInstrumentation 成员 Field 字段Field mInstrumentation_Field = null;try {mInstrumentation_Field = clazz.getDeclaredField("mInstrumentation");} catch (NoSuchFieldException e) {e.printStackTrace();}// 3. 设置 Field mInstrumentation 字段的可访问性mInstrumentation_Field.setAccessible(true);

3、获取 Activity 中的 Instrumentation mInstrumentation 成员字段值

获取 Activity 的 Instrumentation mInstrumentation 成员对象值 , 该成员值就是需要被代理的目标对象 ;

代理者 需要 持有 被代理的目标对象 ;

获取该成员的意义是 , 创建 Instrumentation 代理时, 需要将原始的 Instrumentation 传入代理对象中 ;

        // 4. 获取 Activity 的 Instrumentation mInstrumentation 成员对象值//      获取该成员的意义是 , 创建 Instrumentation 代理时, 需要将原始的 Instrumentation 传入代理对象中Instrumentation mInstrumentation = null;try {mInstrumentation = (Instrumentation) mInstrumentation_Field.get(this);} catch (IllegalAccessException e) {e.printStackTrace();}

4、设置 Activity 中的 Instrumentation mInstrumentation 成员字段值

设置 Activity 中的 Instrumentation mInstrumentation 成员字段值 , 将 Activity 的 Instrumentation mInstrumentation 成员变量 设置为自己定义的 Instrumentation 代理对象 ;

此处使用的是静态代理 ;

        // 5. 将 Activity 的 Instrumentation mInstrumentation 成员变量//      设置为自己定义的 Instrumentation 代理对象try {mInstrumentation_Field.set(this, new InstrumentationProxy(mInstrumentation));} catch (IllegalAccessException e) {e.printStackTrace();}

5、代理类开发

被代理的目标对象是 Activity 中的 Instrumentation mInstrumentation 成员变量 ;

代理类中需要持有上述成员变量 , 通过反射获取该成员 , 并设置给代理者 ;

在代理类中 , 继承 Instrumentation 类 , 这是因为还需要通过反射 , 将代理类设置给 Activity 的 Instrumentation mInstrumentation 成员 , 以达到偷梁换柱的目的 , 档 Activity 调用 Instrumentation mInstrumentation 成员时 , 其实调用的是开发者开发的代理类 ;

在 Android 界面跳转时 , 会自动回调 Activity 中的 Instrumentation mInstrumentation 成员的 execStartActivity 方法 ;

实际上调用的是代理类的 execStartActivity 方法 ;

在代理类 execStartActivity 方法中 , 首先调用持有的 Activity 中原本的 Instrumentation mInstrumentation 成员的 execStartActivity 方法 , 然后在该方法的前面 , 后面 , 可以添加自己的业务逻辑 , 该方法的执行参数也可以进行修改 ;

这样就成功将自己的业务逻辑注入到了 Activity 启动过程中 ;

代码示例 :

package com.example.plugin_hook;import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class InstrumentationProxy extends Instrumentation {private static final String TAG = "InstrumentationProxy";/*** Activity 中原本的 Instrumentation mInstrumentation 成员* 从构造函数中进行初始化*/final Instrumentation orginalInstrumentation;public InstrumentationProxy(Instrumentation orginalInstrumentation) {this.orginalInstrumentation = orginalInstrumentation;}public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {Log.i(TAG, "注入的 Hook 前执行的业务逻辑");// 1. 反射执行 Instrumentation orginalInstrumentation 成员的 execStartActivity 方法Method execStartActivity_Method = null;try {execStartActivity_Method = Instrumentation.class.getDeclaredMethod("execStartActivity",Context.class,IBinder.class,IBinder.class,Activity.class,Intent.class,int.class,Bundle.class);} catch (NoSuchMethodException e) {e.printStackTrace();}// 2. 设置方法可访问性execStartActivity_Method.setAccessible(true);// 3. 执行 Instrumentation orginalInstrumentation 的 execStartActivity 方法//    使用 Object 类型对象接收反射方法执行结果ActivityResult activityResult = null;try {activityResult = (ActivityResult) execStartActivity_Method.invoke(orginalInstrumentation,who,contextThread,token,target,intent,requestCode,options);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}Log.i(TAG, "注入的 Hook 后执行的业务逻辑");return activityResult;}
}

三、完整代码示例


1、主界面代码示例

主界面代码示例 :

package com.example.plugin_hook;import androidx.appcompat.app.AppCompatActivity;import android.app.Activity;
import android.app.Instrumentation;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取按钮 , 并未按钮组件设置点击事件Button button = findViewById(R.id.button);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.i(TAG, "Button OnClickListener onClick");startActivity(new Intent(MainActivity.this, MainActivity2.class));}});hookOnClick(button);hookStartActivity();}@Overridepublic void startActivity(Intent intent) {super.startActivity(intent);}/*** hook Button 组件的 getListenerInfo 方法* @param view*/private void hookOnClick(View view){// 获取 View 的 getListenerInfo 方法Method getListenerInfo = null;try {getListenerInfo = View.class.getDeclaredMethod("getListenerInfo");} catch (NoSuchMethodException e) {e.printStackTrace();}// 执行所有的反射方法 , 设置成员变量 之前 , 都要设置可见性getListenerInfo.setAccessible(true);// 执行 View view 对象的 getListenerInfo 方法Object mListenerInfo = null;try {mListenerInfo = getListenerInfo.invoke(view);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}// 反射获取 OnClickListener 成员// ① 先根据全类名获取 ListenerInfo 字节码Class<?> clazz = null;try {clazz = Class.forName("android.view.View$ListenerInfo");} catch (ClassNotFoundException e) {e.printStackTrace();}// ② 获取 android.view.View.ListenerInfo 中的 mOnClickListener 成员Field field = null;try {field = clazz.getField("mOnClickListener");} catch (NoSuchFieldException e) {e.printStackTrace();}// ③ 设置该字段访问性, 执行所有的反射方法 , 设置成员变量 之前 , 都要设置可见性field.setAccessible(true);// ④ 获取 mOnClickListener 成员变量View.OnClickListener mOnClickListener = null;try {mOnClickListener = (View.OnClickListener) field.get(mListenerInfo);} catch (IllegalAccessException e) {e.printStackTrace();}// ⑤ 修改 View 的 ListenerInfo 成员的 mOnClickListener 成员// 其中 ListenerInfo 成员 是try {View.OnClickListener finalMOnClickListener = mOnClickListener;field.set(mListenerInfo, new View.OnClickListener(){@Overridepublic void onClick(View v) {Log.i(TAG, "Hook Before");finalMOnClickListener.onClick(view);Log.i(TAG, "Hook After");}});} catch (IllegalAccessException e) {e.printStackTrace();}}/*** Hook Activity 界面启动过程* 钩住 Instrumentation 的 execStartActivity 方法* 向该方法中注入自定义的业务逻辑*/private void hookStartActivity(){// 1. 获取 Activity 字节码文件//    字节码文件是所有反射操作的入口Class<?> clazz = Activity.class;// 2. 获取 Activity 的 Instrumentation mInstrumentation 成员 Field 字段Field mInstrumentation_Field = null;try {mInstrumentation_Field = clazz.getDeclaredField("mInstrumentation");} catch (NoSuchFieldException e) {e.printStackTrace();}// 3. 设置 Field mInstrumentation 字段的可访问性mInstrumentation_Field.setAccessible(true);// 4. 获取 Activity 的 Instrumentation mInstrumentation 成员对象值//      获取该成员的意义是 , 创建 Instrumentation 代理时, 需要将原始的 Instrumentation 传入代理对象中Instrumentation mInstrumentation = null;try {mInstrumentation = (Instrumentation) mInstrumentation_Field.get(this);} catch (IllegalAccessException e) {e.printStackTrace();}// 5. 将 Activity 的 Instrumentation mInstrumentation 成员变量//      设置为自己定义的 Instrumentation 代理对象try {mInstrumentation_Field.set(this, new InstrumentationProxy(mInstrumentation));} catch (IllegalAccessException e) {e.printStackTrace();}}}

2、代理类代码示例

代理类代码示例 :

package com.example.plugin_hook;import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class InstrumentationProxy extends Instrumentation {private static final String TAG = "InstrumentationProxy";/*** Activity 中原本的 Instrumentation mInstrumentation 成员* 从构造函数中进行初始化*/final Instrumentation orginalInstrumentation;public InstrumentationProxy(Instrumentation orginalInstrumentation) {this.orginalInstrumentation = orginalInstrumentation;}public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {Log.i(TAG, "注入的 Hook 前执行的业务逻辑");// 1. 反射执行 Instrumentation orginalInstrumentation 成员的 execStartActivity 方法Method execStartActivity_Method = null;try {execStartActivity_Method = Instrumentation.class.getDeclaredMethod("execStartActivity",Context.class,IBinder.class,IBinder.class,Activity.class,Intent.class,int.class,Bundle.class);} catch (NoSuchMethodException e) {e.printStackTrace();}// 2. 设置方法可访问性execStartActivity_Method.setAccessible(true);// 3. 执行 Instrumentation orginalInstrumentation 的 execStartActivity 方法//    使用 Object 类型对象接收反射方法执行结果ActivityResult activityResult = null;try {activityResult = (ActivityResult) execStartActivity_Method.invoke(orginalInstrumentation,who,contextThread,token,target,intent,requestCode,options);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}Log.i(TAG, "注入的 Hook 后执行的业务逻辑");return activityResult;}
}

3、跳转的界面

跳转的界面 :

package com.example.plugin_hook;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;public class MainActivity2 extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main2);}
}

4、执行结果

按钮点击事件 , 在调用按钮事件的前后 , 注入的业务逻辑 , 分别打印 Hook BeforeHook After ;

Activity 启动过程 , Hook 住了 Activity 的 Instrumentation mInstrumentation 成员的 execStartActivity 方法 , 在调用该方法的 前后 , 各注入的业务逻辑中打印 注入的 Hook 前执行的业务逻辑注入的 Hook 后执行的业务逻辑 ;

I/MainActivity: Hook Before
I/MainActivity: Button OnClickListener onClick
I/InstrumentationProxy: 注入的 Hook 前执行的业务逻辑
I/InstrumentationProxy: 注入的 Hook 后执行的业务逻辑
I/MainActivity: Hook After

四、博客资源


博客资源 :

  • GitHub : https://github.com/han1202012/Plugin_Hook

【Android 插件化】Hook 插件化框架 ( Hook Activity 启动过程 | 静态代理 )相关推荐

  1. Android系统(117)---Activity启动过程

    Activity启动过程 ###一些基本的概念 ActivityManagerServices,简称AMS,服务端对象,负责系统中所有Activity的生命周期 ActivityThread,App的 ...

  2. Android 面试必备 - 系统、App、Activity 启动过程

    前言 最近准备更新 Android 面试必备基础知识系列,有兴趣的可以关注我的微信公众号 stormjun94,有更新时,第一时间会在微信公众号上面发布,同时,也会同步在 GitHub 上面更新,如果 ...

  3. Android深入四大组件(五)Android8.0 根Activity启动过程(后篇)

    前言 在几个月前我写了Android深入四大组件(一)应用程序启动过程(前篇)和Android深入四大组件(一)应用程序启动过程(后篇)这两篇文章,它们都是基于Android 7.0,当我开始阅读An ...

  4. Android世界第一个activity启动过程

    Android世界第一个activity启动过程 第一次使用Markdown,感觉不错. Android系统从按下开机键一直到launcher的出现,是一个如何的过程,中间都做出了什么操作呢.带着这些 ...

  5. Activity启动过程详解(Android P)

    本章我们来分析Activity的启动过程. 我们知道,Activity可以通过两种方式启动:一种是点击应用程序图标,Launcher会启动主Activity:另一种是在应用程序内部,调用startAc ...

  6. Android深入四大组件(六)Android8.0 根Activity启动过程(前篇)

    相关文章 Android深入四大组件系列 Android系统启动系列 Android应用程序进程系列 Android深入解析AMS系列 前言 在几个月前我写了Android深入四大组件(一)应用程序启 ...

  7. Android深入四大组件(七)Android8.0 根Activity启动过程(后篇)

    相关文章 Android深入四大组件系列 Android系统启动系列 Android应用程序进程系列 Android深入解析AMS系列 前言 在几个月前我写了Android深入四大组件(一)应用程序启 ...

  8. Android进阶——Android四大组件启动机制之Activity启动过程

    前言 Activity启动过程涉及到的比较多的知识点有Binder的跨进程通讯,建议先看完Binder的跨进程通讯再来阅读本篇文章,在文章阅读开始,我们先要理解Activity启动模型,再者去理解有关 ...

  9. Android FrameWork——Activity启动过程详解

    前面发了blog分析了ActivityManager框架的大体结构,主要就是一个进程通信机制,今天我通过深入Activity的启动过程再次深入到ActivityManager框架,对其进行一个更深入的 ...

最新文章

  1. 不容错过的Pandas小技巧:万能转格式、轻松合并、压缩数据,让数据分析更高效...
  2. CTF---Web入门第四题 Forms
  3. 【实验】综合实验-咔咔咔还是一顿整
  4. 从0搭建在线聊天室,只需4步!
  5. 技术实践 | Android 设备音视频兼容性适配
  6. i2c--insmod
  7. 【IT笔试面试题整理】删除无序链表中重复的节点
  8. 软考知识点梳理--鱼骨图
  9. 一张图带你看懂 ,web前端开发应该知道的HTML5六大趋势
  10. python的设计哲学是优雅明确简单_Python简单教程
  11. php不能header跳转页面,PHP问题:php header方法跳转页面问题
  12. mysql基础5-数据的操作
  13. eclipse(Kepler Service Release 2)问题记录
  14. 《计算机网络》谢希仁第七版课后答案完整版
  15. Java 全国省市接口
  16. 使用catagory类别给控件加边框
  17. 常见物联网无线组网方式
  18. 帧定格(用于定格画面添加字幕或者图片)
  19. 魅族路由器(极速版)刷老毛子(padavad)固件-全网最详细教程
  20. ocsp和ldap 区别_《脑梗塞ocsp分型和治疗》.ppt

热门文章

  1. 数学图形之克莱因瓶(klein bottle)
  2. 汇编程序开发环境搭配
  3. Linux vim 梳理
  4. CF911F Tree Destruction (树的直径,贪心)
  5. 洛谷 P3539 [POI2012]ROZ-Fibonacci Representation 解题报告
  6. 201521123091 《Java程序设计》第3周学习总结
  7. 网易笔试——混合颜料
  8. 一个经典的字母排列算法
  9. Android 之 Shape (圆角输入框)
  10. Oracle Linux 6.1 说明