android状态机实现原理
从源代码角度去分析状态机的实现过程。
主要涉及到的文件有:
frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java
frameworks/base/core/java/com/android/internal/util/StateMachine.java
frameworks/base/core/java/com/android/internal/util/State.java
frameworks/base/core/java/com/android/internal/util/IState.java
其中IState是一个接口类:
上述的方法会由StateMachine来支配,决定何时调用,现有这个概念即可。
接着看StateMachine类中一些重要的内嵌类和函数。
- public static class ProcessedMessageInfo {//包含一个状态的所有信息
- private int what;
- private State state;//这个经常用到,表示当前处于那个状态
- private State orgState;//表示接收到消息的状态
- ........................................
- ProcessedMessageInfo(Message message, State state, State orgState) {
- update(message, state, orgState);//更新当前状态
- }
- ..........................................
- public void update(Message message, State state, State orgState) {
- this.what = message.what;
- this.state = state;
- this.orgState = orgState;
- }
- .......................................
- }
- private static class ProcessedMessages {//保存最近处理的20条消息,具体包括state,发送的message等
- private static final int DEFAULT_SIZE = 20;//默认的最大状态个数,这个不是指所有的状态,而是当前活动状态往父类追溯得到的所有类的状态
- private Vector<ProcessedMessageInfo> mMessages = new Vector<ProcessedMessageInfo>();
- private int mMaxSize = DEFAULT_SIZE;
- ....................................
- ProcessedMessageInfo get(int index) {//根据索引获取状态信息
- int nextIndex = mOldestIndex + index;
- if (nextIndex >= mMaxSize) {
- nextIndex -= mMaxSize;
- }
- if (nextIndex >= size()) {
- return null;
- } else {
- return mMessages.get(nextIndex);
- }
- }
- .........................................
- void add(Message message, State state, State orgState) {//orgState为最底层状态节点,state为有能力处理message的节点,他们可能相等,或则state为orgState的祖类节点
- mCount += 1;
- if (mMessages.size() < mMaxSize) {
- mMessages.add(new ProcessedMessageInfo(message, state, orgState));
- } else {
- ProcessedMessageInfo pmi = mMessages.get(mOldestIndex);
- mOldestIndex += 1;
- if (mOldestIndex >= mMaxSize) {
- mOldestIndex = 0;
- }
- pmi.update(message, state, orgState);
- }
- }
- }
- private static class SmHandler extends Handler {
- .................................
- private StateInfo mStateStack[];//这里存放的是当前state以及父类的state
- private int mStateStackTopIndex = -1;//mStateStack数组的下标索引
- private StateInfo mTempStateStack[];//状态信息缓存区
- private HaltingState mHaltingState = new HaltingState();//状态挂起时候才会用到,一般用不上
- private QuittingState mQuittingState = new QuittingState();//状态退出时候才会用上,一般用不上
- private StateMachine mSm;//全局的StateMachine引用,在构造函数中this指针赋的值
- private HashMap<State, StateInfo> mStateInfo =
- new HashMap<State, StateInfo>();//保存所有加入的state信息
- private State mInitialState;//初始化的状态
- private State mDestState;//切换时新的目标状态
- @Override
- public final void handleMessage(Message msg) {
- processMsg(msg);//处理接收到的消息
- performTransitions();//处理就状态到新状态的切换
- if (mDbg) Log.d(TAG, "handleMessage: X");
- }
- ..........................
- }
到这里,还是先把wifistatemachine的状态图写出来,以便好理解。
比如,如果当前状态为mDriverFailedState,则上面mStateStack存放的是[mDefaultState,mDriverUnloadedState,mDriverFailedState]三个状态的信息
StateMachine的构造函数做了些什么?
- protected StateMachine(String name) {
- mSmThread = new HandlerThread(name);
- mSmThread.start();
- Looper looper = mSmThread.getLooper();
- initStateMachine(name, looper);
- }
而在initStateMachine方法中:
- private void initStateMachine(String name, Looper looper) {
- mName = name;
- mSmHandler = new SmHandler(looper, this); //mSmHandler是一个全局的handler,后面常用到
- }
- private SmHandler(Looper looper, StateMachine sm) {
- super(looper);
- mSm = sm;//mSm是一个全局的变量,后面经常用到
- addState(mHaltingState, null);//状态挂起的时候调用
- addState(mQuittingState, null);//状态退出的时候调用
- }
WifiStateMachine的构造函数主要做了些什么?
主要是调用addState方法将wifi中创建的状态加入状态机中,最后setInitialState来设置初始化状态。具体过程如下:
- protected final void addState(State state, State parent) {//将state添加到父节点parent下,如果parent为null,则state作为父节点
- mSmHandler.addState(state, parent);
- }
- private final StateInfo addState(State state, State parent) {
- if (mDbg) {
- Log.d(TAG, "addStateInternal: E state=" + state.getName()
- + ",parent=" + ((parent == null) ? "" : parent.getName()));
- }
- StateInfo parentStateInfo = null;
- if (parent != null) {
- parentStateInfo = mStateInfo.get(parent);//取出父节点的parentStateInfo信息
- if (parentStateInfo == null) { //如果父节点为null,则递归调用,把当前节点作为父节点
- // Recursively add our parent as it's not been added yet.
- parentStateInfo = addState(parent, null);
- }
- }
- StateInfo stateInfo = mStateInfo.get(state);//新节点,肯定为null了
- if (stateInfo == null) {
- stateInfo = new StateInfo();
- mStateInfo.put(state, stateInfo);//将state和stateInfo放入哈系表中,以后根据state即可取出stateInfo信息,前面说过,全局变量mStateInfo哈系表保存了所有state信息
- }
- // Validate that we aren't adding the same state in two different hierarchies.
- if ((stateInfo.parentStateInfo != null) && //新创建还没有赋值,肯定为null啦,否则就抛出异常了
- (stateInfo.parentStateInfo != parentStateInfo)) {
- throw new RuntimeException("state already added");
- }
- stateInfo.state = state;
- stateInfo.parentStateInfo = parentStateInfo;//以后通过state可以找到父节点,一直递归,如果state的父节点为null,则表示到了顶部
- stateInfo.active = false; //时候是当前活动状态标志
- if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo);
- return stateInfo;
- }
这样,通过上面的addState方法,最终形成了上图所示的树形结构。在使用之前,还要设置state的初始化状态:
- /**
- * Set the initial state. This must be invoked before
- * and messages are sent to the state machine.
- *
- * @param initialState is the state which will receive the first message.
- */
- protected final void setInitialState(State initialState) {
- mSmHandler.setInitialState(initialState);
- }
注释已经说的很清楚,这是第一次接收到消息时候进入的状态:
- private final void setInitialState(State initialState) {
- if (mDbg) Log.d(TAG, "setInitialState: initialState" + initialState.getName());
- mInitialState = initialState;//先简单的保存到全局变量中,后续才用到
- }
这样初始化工作完成,WifiStateMachine的构造函数最后调用start()来启动状态机,它的实现方法在父类StateMachine中:
- public void start() {
- // mSmHandler can be null if the state machine has quit.
- if (mSmHandler == null) return;//mSmHandler引用在前面构造函数中就赋值了,肯定不为null了
- /** Send the complete construction message */
- mSmHandler.completeConstruction();
- }
- }
来看completeConstruction方法的实现:
- private final void completeConstruction() {
- if (mDbg) Log.d(TAG, "completeConstruction: E");
- /**
- * Determine the maximum depth of the state hierarchy
- * so we can allocate the state stacks.
- */
- int maxDepth = 0;
- for (StateInfo si : mStateInfo.values()) {//这个for循环就是遍历前面添加到哈系表中的状态,找出树的最大深度,根据前面的树形表可以看出,最大深度为5
- int depth = 0;
- for (StateInfo i = si; i != null; depth++) {
- i = i.parentStateInfo;
- }
- if (maxDepth < depth) {
- maxDepth = depth;
- }
- }
- if (mDbg) Log.d(TAG, "completeConstruction: maxDepth=" + maxDepth);
- mStateStack = new StateInfo[maxDepth];//这个是最后存放当前活动state的,可以看到要得到最大深度的作用就是为了创建数组,因为当前活动state以及父类家族最多就为maxDepth
- mTempStateStack = new StateInfo[maxDepth];//这个是暂时存放state的
- setupInitialStateStack();
- /**
- * Construction is complete call all enter methods
- * starting at the first entry.
- */
- mIsConstructionCompleted = true;
- mMsg = obtainMessage(SM_INIT_CMD);
- invokeEnterMethods(0);
- /**
- * Perform any transitions requested by the enter methods
- */
- performTransitions();
- if (mDbg) Log.d(TAG, "completeConstruction: X");
- }
接着下一句是setupInitialStateStack方法:
- private final void setupInitialStateStack() {
- if (mDbg) {
- Log.d(TAG, "setupInitialStateStack: E mInitialState="
- + mInitialState.getName());
- }
- StateInfo curStateInfo = mStateInfo.get(mInitialState);//取出初始化state,前面已经赋值过,这里为WifiStateMachine中mInitialState对应的stateInfo
- for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
- mTempStateStack[mTempStateStackCount] = curStateInfo;//最后mTempStateStack存放的值为[mInitialState,mDefaultState]对应的stateInfo
- curStateInfo = curStateInfo.parentStateInfo;
- }
- // Empty the StateStack
- mStateStackTopIndex = -1;
- moveTempStateStackToStateStack();
- }
moveTempStateStackToStateStack方法就是将mTempStateStack的值倒序放到mStateStack中:
- private final int moveTempStateStackToStateStack() {
- int startingIndex = mStateStackTopIndex + 1;// -1 + 1 = 0;
- int i = mTempStateStackCount - 1;//第一次进入,2 - 1 = 1;
- int j = startingIndex;
- while (i >= 0) {
- if (mDbg) Log.d(TAG, "moveTempStackToStateStack: i=" + i + ",j=" + j);
- mStateStack[j] = mTempStateStack[i];
- j += 1;
- i -= 1;
- }
- mStateStackTopIndex = j - 1;// 2 - 1 = 1
- if (mDbg) {
- Log.d(TAG, "moveTempStackToStateStack: X mStateStackTop="
- + mStateStackTopIndex + ",startingIndex=" + startingIndex
- + ",Top=" + mStateStack[mStateStackTopIndex].state.getName());
- }
- return startingIndex; //0
- }
这样,当前状态信息就保存在mStateStack中,为[mDefaultState, mInitialState]对应的状态信息。
回到completeConstruction中,接着invokeEnterMethods方法:
- private final void invokeEnterMethods(int stateStackEnteringIndex) {
- for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {//前面分析可以,mStateStackTopIndex为1
- if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());
- mStateStack[i].state.enter();//依次调用活动状态的enter方法,可以看到是从最顶层父类依次往下调用的
- mStateStack[i].active = true; //把当前state置为true
- }
- }
mDefaultState重写enter方法,父类State的enter方法什么也不做;InitialState有重写enter方法:
- class InitialState extends State {
- @Override
- //TODO: could move logging into a common class
- public void enter() {
- ......................................
- if (WifiNative.isDriverLoaded()) {
- transitionTo(mDriverLoadedState);//如果我们打开过wifi,状态就会切换到mDriverLoadedState去了
- }
- else {
- transitionTo(mDriverUnloadedState);//第一次打开是没有load过的,所以进入unload状态
- }
- .................................
- }
- }
- protected final void transitionTo(IState destState) {//IState是所有state的接口类
- mSmHandler.transitionTo(destState);调用handler方法来处理
- }
- private final void transitionTo(IState destState) {
- mDestState = (State) destState;//先保存到变量中,后续真正状态切换时候才用到
- if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + mDestState.getName());
- }
这样invokeEnterMethods方法就完成了,接着是performTransitions方法,这是真正处理状态切换的方法了:
- private void performTransitions() {
- .....................
- State destState = null;
- while (mDestState != null) {
- ......................................
- destState = mDestState;//destState为mDriverUnLoadedState
- mDestState = null;
- ..............................
- StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
- invokeExitMethods(commonStateInfo);
- int stateStackEnteringIndex = moveTempStateStackToStateStack();
- invokeEnterMethods(stateStackEnteringIndex);
- moveDeferredMessageAtFrontOfQueue();
- }
- if (destState != null) {
- if (destState == mQuittingState) {
- cleanupAfterQuitting();
- } else if (destState == mHaltingState) {
- mSm.halting();
- }
- }
- }
setupTempStateStackWithStatesToEnter方法主要是把当前活动state家族放入mTempStateStack中,并且返回顶层节点的信息,这样,mTempStateStack保存信息为[mDriverUnLoadedState, mDefaultState]的信息;
invokeExitMethods方法则是从当前活动state顶层节点一次调用exit方法,并且设置state的active标记为false;这里要注意当前活动的还是是mStateStack中的信息,即[mDefaultState, mInitialState]对应的状态信息,exit方法一般是做一些善后工作。处理完成后
mStateStackTopIndex又自减为-1。
moveTempStateStackToStateStack和invokeEnterMethods方法前面已经分析过。完成后mStateStack的状态信息变为[mDefaultState,mDriverUnLoadedState]
最后一个函数moveDeferredMessageAtFrontOfQueue刷新消息队列的排序。该方法就是将mDeferredMessages容器中的消息按先后顺序发送出去,然后清空容器。至于消息是如何加入容器的,后面遇到再分析。
这样start方法就完成,整个WifiStateMachine构造函数也建立完成了。
如果我们打开wifi,会在WifiService中调用setWifiEnabled - >mWifiStateMachine.setWifiEnabled来启动。setWifiEnabled的状态切换过程为:
- public void setWifiEnabled(boolean enable) {
- mLastEnableUid.set(Binder.getCallingUid());
- if (enable) {
- /* Argument is the state that is entered prior to load */
- sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
- sendMessage(CMD_START_SUPPLICANT);
- } else {
- sendMessage(CMD_STOP_SUPPLICANT);
- /* Argument is the state that is entered upon success */
- sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));
- }
- }
sendMessage方法是StateMachine实现的,它封装了Handler类的sendMessage方法,会被SmHandler类的handleMessage来接收处理。而它是调用一下两个方法来处理消息的:
- processMsg(msg);
- performTransitions();
先看第一个:
- private final void processMsg(Message msg) {
- StateInfo curStateInfo = mStateStack[mStateStackTopIndex];//mStateStack保存信息的顺序为顶层节点->底层节点,mStateStackTopIndex为数组个数,这里取出的就为最底层节点的状态信息
- if (mDbg) {
- Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
- }
- while (!curStateInfo.state.processMessage(msg)) {//所以从底层节点开始往上遍历,调用processMessage来处理消息,直到找到一个可以处理的节点后返回HANDLED(true),条件退出
- /**
- * Not processed
- */
- curStateInfo = curStateInfo.parentStateInfo;
- if (curStateInfo == null) {//找到顶层节点了,才用unhandledMessage,它不做什么事情,打印一句LOG信息而已
- /**
- * No parents left so it's not handled
- */
- mSm.unhandledMessage(msg);
- if (isQuit(msg)) {//如果命令是SM_QUIT_CMD才会退出,一般情况下是不会退出的
- transitionTo(mQuittingState);
- }
- break;
- }
- if (mDbg) {
- Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
- }
- }
- /**
- * Record that we processed the message
- */
- if (curStateInfo != null) {
- State orgState = mStateStack[mStateStackTopIndex].state;
- mProcessedMessages.add(msg, curStateInfo.state, orgState);//保存处理processMessage的消息到mProcessedMessages中,作为一个记录,一般保存最近的20条,这个最大值可以自己定义
- } else {
- mProcessedMessages.add(msg, null, null);
- }
- }
这时mStateStack的状态信息变为[mDefaultState, mDriverUnLoadedState],先所以调用mDriverUnLoadedState的processMessage方法,而前面发送的消息为:
- sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
- sendMessage(CMD_START_SUPPLICANT);
第一句的CMD_LOAD_DRIVER,发送给应用层的消息为WIFI_STATE_ENABLING:
- class DriverUnloadedState extends State {
- @Override
- public void enter() {
- if (DBG) log(getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- }
- @Override
- public boolean processMessage(Message message) {
- if (DBG) log(getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_LOAD_DRIVER:
- mWifiP2pChannel.sendMessage(WIFI_ENABLE_PENDING);//这是发送消息给WifiP2pService,WifiP2pService会响应并返回消息WIFI_ENABLE_PROCEED,其中过程有点复杂,后续再分析
- transitionTo(mWaitForP2pDisableState);//状态切换到了mWaitForP2pDisableState,其他好像没有做什么
- break;
- case WifiP2pService.P2P_ENABLE_PENDING:
- mReplyChannel.replyToMessage(message, P2P_ENABLE_PROCEED);
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
- }
WaitForP2pDisableState的enter做什么了?
状态已经进入mWaitForP2pDisableState中了:
- class WaitForP2pDisableState extends State {
- .............................
- @Override
- public boolean processMessage(Message message) {
- case WifiP2pService.WIFI_ENABLE_PROCEED: //响应WifiP2pService消息
- //restore argument from original message (CMD_LOAD_DRIVER)
- message.arg1 = mSavedArg;
- transitionTo(mDriverLoadingState);
- break;
- case CMD_LOAD_DRIVER:
- case CMD_UNLOAD_DRIVER:
- case CMD_START_SUPPLICANT:
- ..........................
- deferMessage(message);
- .............................
deferMessage将消息放入mDeferredMessages容器中,前面有提及过,作用是要把消息保存起来,等切换到下一个状态后,再将消息发送出去,让下一个状态接收;接下来的performTransitions方法中会将消息发送出去,并且在切换下一个状态前清空容器。
这时候状态在WaitForP2pDisableState中,WifiP2pService接收到消息WIFI_ENABLE_PENDING后,返回WIFI_ENABLE_PROCEED作为响应;
所以执行transitionTo(mDriverLoadingState)进入下一个状态。
processMsg就处理完成了,接着的performTransitions前面已经分析过,主要工作为调用当前状态的exit方法;切换新状态到mSupplicantStartingState,并调用新状态的enter方法,静等下一个消息的到来。
根据前面的分析可知,这时候先执行的是mDriverLoadingState的enter方法:
- class DriverLoadingState extends State {
- @Override
- public void enter() {
- if (DBG) log(getName() + "\n");
- EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- final Message message = new Message();
- message.copyFrom(getCurrentMessage());
- /* TODO: add a timeout to fail when driver load is hung.
- * Similarly for driver unload.
- */
- new Thread(new Runnable() {
- public void run() {
- mWakeLock.acquire();
- //enabling state
- switch(message.arg1) {
- case WIFI_STATE_ENABLING:
- setWifiState(WIFI_STATE_ENABLING);
- break;
- if(WifiNative.loadDriver()) {
- if (DBG) log("Driver load successful");
- sendMessage(CMD_LOAD_DRIVER_SUCCESS);
- } else {
- loge("Failed to load driver!");
- switch(message.arg1) {
- case WIFI_STATE_ENABLING:
- setWifiState(WIFI_STATE_UNKNOWN);
- break;
- case WIFI_AP_STATE_ENABLING:
- setWifiApState(WIFI_AP_STATE_FAILED);
- break;
- }
- sendMessage(CMD_LOAD_DRIVER_FAILURE);
- }
- mWakeLock.release();
- }
- }).start();
- @Override
- public boolean processMessage(Message message) {
- if (DBG) log(getName() + message.toString() + "\n");
- switch (message.what) {
- case CMD_LOAD_DRIVER_SUCCESS:
- transitionTo(mDriverLoadedState);
- break;
- case CMD_LOAD_DRIVER_FAILURE:
- transitionTo(mDriverFailedState);
- break;
- case CMD_LOAD_DRIVER:
- case CMD_UNLOAD_DRIVER:
- case CMD_START_SUPPLICANT:
- case CMD_STOP_SUPPLICANT:
- case CMD_START_AP:
- case CMD_STOP_AP:
- case CMD_START_DRIVER:
- case CMD_STOP_DRIVER:
- case CMD_SET_SCAN_MODE:
- case CMD_SET_SCAN_TYPE:
- case CMD_SET_HIGH_PERF_MODE:
- case CMD_SET_COUNTRY_CODE:
- case CMD_SET_FREQUENCY_BAND:
- case CMD_START_PACKET_FILTERING:
- case CMD_STOP_PACKET_FILTERING:
- deferMessage(message);
- break;
- default:
- return NOT_HANDLED;
- }
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- return HANDLED;
- }
enter线程中的消息为前面发送的WIFI_STATE_ENABLING,setWifiState的作用是发送广播通知应用层wifi状态的改变,并且加载JNI的wifi驱动,成功后还发送CMD_LOAD_DRIVER_SUCCESS消息。
接着第二句命令CMD_START_SUPPLICANT,状态在mDriverLoadingState中,执行processMessage方法,这时候会先接收前面的延时消息CMD_LOAD_DRIVER_SUCCESS,接着接收CMD_LOAD_DRIVER,CMD_START_SUPPLICANT
状态就切换到了mDriverLoadedState,并且将其他两条消息延后再传给下一个状态。
后续WifiService会根据逻辑需求,发送各种命令过来进行状态的切换,但流程都和上述分析的一样,状态机能确保各种状态有条不紊的切换并保持控制流程的清晰明了。
最后画一幅流程图如下:
android状态机实现原理相关推荐
- 状态模式/Android状态机/微信多人语音
最近在做类似微信多人语音,视频聊天功能,用到了Android的状态机,借此写写自己的理解 状态模式 对状态模式的理解: 不同的状态对应不同的行为,当一个对象的状态改变了,那么该对象的行为也随之改变!通 ...
- Android Touch事件原理加实例分析
Android中有各种各样的事件,以响应用户的操作.这些事件可以分为按键事件和触屏事件.而Touch事件是触屏事件的基础事件,在进行Android开发时经常会用到,所以非常有必要深入理解它的原理机制. ...
- Android 插件化原理学习 —— Hook 机制之动态代理
前言 为了实现 App 的快速迭代更新,基于 H5 Hybrid 的解决方案有很多,由于 webview 本身的性能问题,也随之出现了很多基于 JS 引擎实现的原生渲染的方案,例如 React Nat ...
- 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | ActivityThread 后续分析 | Application 替换位置 )
文章目录 一.ActivityThread 后续分析 二.ActivityThread 相关源码 三.Application 替换位置 dex 解密时 , 需要将 代理 Application 替换为 ...
- 手机内存解读以及android刷机原理
手机内存分为:机身内存.RAM.ROM 机身内存:相当于 电脑的硬盘 这个一般可以外加SD卡扩充: RAM:相当于 电脑的内存条 可读写,掉电清空 ROM:相当于 电脑的 BIOS ROM 原则上只读 ...
- Android 插件化原理解析——Activity生命周期管理
之前的 Android插件化原理解析 系列文章揭开了Hook机制的神秘面纱,现在我们手握倚天屠龙,那么如何通过这种技术完成插件化方案呢?具体来说,插件中的Activity,Service等组件如何在A ...
- Android代码入侵原理解析(一)
Original 2017-05-06 付超红 滴滴安全应急响应中心 2017年初,在滴滴安全沙龙上,滴滴出行安全专家--付超红,针对App的攻与防进行了分享.会后大家对这个议题反响热烈,纷纷求详情求 ...
- Android 插件化原理解析——Hook机制之AMSPMS
在前面的文章中我们介绍了DroidPlugin的Hook机制,也就是代理方式和Binder Hook:插件框架通过AOP实现了插件使用和开发的透明性.在讲述DroidPlugin如何实现四大组件的插件 ...
- android r.java 原理,深入理解Android消息处理系统原理
Android应用程序也是消息驱动的,按道理来说也应该提供消息循环机制.实际上谷歌参考了Windows的消息循环机制,也在Android系统中实现了消息循环机制. Android通过Looper.Ha ...
最新文章
- MongoDB 标准连接字符串
- WISMO模块GPRS上网设置的过程
- 程序可以在硬件之间发送吗_你知道硬件、软件工程师之间,还有一个固件工程师吗?...
- FFT C语言 修改了matlab
- 用数学方法分析哪类游戏中的AI难度最大
- 辽宁活跃ip段_有泰国女排影子!激情辽宁女排,打出快乐排球,输了比赛赢了球迷...
- CMake 使用笔记
- C51编程在不同内存空间(data xdata bdata)定义变量的注意事项
- 3. 说清 Observable
- 两个app应用之间的跳转
- android之自定义弹框
- 年终盘点丨2021边缘计算大事记
- 团队项目绩效考核方案表
- 【华人学者风采】刘小平 中山大学
- Mac快速创建文件、文件夹
- 杭电多校第七场 1011	Kejin Player HDU(6656)
- m35c android 4.4,手机实时动态:评测:索尼M35c的整体性能简介及性价比如何
- 《论语》全译——先进篇第十一
- 16秋计算机科学与技术鲁嘉华第七章
- Densely Connected Convolutional Networks(论文解读三)
热门文章
- 【Google Play】正式版上架流程 ( 创建版本 | 设置国家地区 | 发布正式版 )
- 【错误记录】Android 编译时技术版本警告 ( 注解处理器与主应用支持的 Java 版本不匹配 )
- 【计算理论】可判定性 ( 丘奇-图灵论题 | 可判定性引入 | 图灵机语言 | 图灵机结果 | 判定机 | 部分函数与全部函数 | 可判定性定义 )
- Hadoop-2.8.5的HA集群搭建
- 求不同字母全排列两种递归模板
- MYSQL 5.7 主从复制 -----GTID说明与限制 原创
- Item 14: 如果函数不会抛出异常就把它们声明为noexcept
- Hadoop 资源列表
- CodeDom 笔记整理
- 优化内存中DataTable搜索速度,IP区域汇总