本文以Android 7.1为基础

最近在做蓝牙开发,研究了一下蓝牙的启动流程,总结一下

Google在Android源码中推出了它和博通公司一起开发的BlueDroid以替代BlueZ。BlueZ的创始者,高通公司也将在基于其芯片的Android参考设计中去除BlueZ,支持BlueDroid。相比BlueZ,BlueDroid最值得称道的地方就是其框架结构变得更为简洁和清晰。对我们工程师来说这也是个不错的福利,清晰、简洁的架构使我们在debug过程中思路更清晰;

蓝牙的总体流程图

从流程图我们可以看出来 蓝牙应用通过binder和系统蓝牙Service进行通讯 ,然后通过Jin与蓝牙HAL层进行通讯。

按层级划分

Bluetooth Service(Java层)代码路径

frameworks/base/core/java/Android/Bluetooth:

Bluetooth 应用层代码路径

packages/apps/Bluetooth

Bluetooth协议层代码

system/bt/

涉及的总共路径:

frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
frameworks/base/core/java/android/bluetooth/BluetoothManagerService.java
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java
packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
system/bt/btif/src/btif_dm.c
system/bt/btif/include/btif_common.h
hardware/libhardware/include/hardware/bluetooth.h 

一.将蓝牙作为sink模式 配置

sink模式一般是车机端需要设置的模式,用于链接手机之后可以播放蓝牙音乐,获取联系人,和电话控制等等

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/Config.java
有如下两个参数控制是否是 sink端boolean isA2dpSinkEnabled = SystemProperties.getBoolean("persist.service.bt.a2dp.sink", false);boolean isHfpClientEnabled = SystemProperties.getBoolean("persist.service.bt.hfp.client",false);

我们需要在编译源码的时候去配置成sink模式:

device/qcom/msmxxx_64/system.prop
添加如下配置persist.service.bt.a2dp.sink=true
persist.service.bt.hfp.client=true

再具体的配置信息在如下配置中进行设置具体支持那种profile

packages/apps/Bluetooth/res/values/config.xml
<resources><bool name="profile_supported_a2dp">true</bool><bool name="profile_supported_a2dp_sink">false</bool><bool name="profile_supported_hdp">true</bool><bool name="profile_supported_hs_hfp">true</bool><bool name="profile_supported_hfpclient">false</bool><bool name="profile_supported_hid">true</bool><bool name="profile_supported_opp">true</bool><bool name="profile_supported_pan">true</bool><bool name="profile_supported_pbap">true</bool><bool name="profile_supported_gatt">true</bool><bool name="pbap_include_photos_in_vcard">true</bool><bool name="pbap_use_profile_for_owner_vcard">true</bool><bool name="profile_supported_map">true</bool><bool name="profile_supported_avrcp_controller">false</bool><bool name="profile_supported_sap">false</bool><bool name="profile_supported_pbapclient">false</bool><bool name="strict_location_check">true</bool>
</resources>

当然修改上面的配置我们可以在如下路径配置

vendor/qcom/opensource/bluetooth/res/values/config.xml
<resources><bool name="profile_supported_ftp">true</bool><bool name="profile_supported_map">false</bool><bool name="profile_supported_sap">true</bool><bool name="profile_supported_dun">true</bool>
</resources>

如果 packages/apps/Bluetooth/res/values/config.xml 和 vendor/qcom/opensource/bluetooth/res/values/config.xml 都配置了如下配置 或者是配置的两个Boolean 值是反向的,系统会依据 vendor/qcom/opensource/bluetooth/res/values/config.xml 配置为最终结果,配置完成之后编译系统,烧录系统就可以作为sink端使用,也就是接收端.

二.启动流程分析

首先我们先看一下时序图

我们调用蓝牙的时候使用的是Bluetooth的 BluetoothAdapter.java 类 中的enable方法

路径如下:

frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
    public boolean enable() {android.util.SeempLog.record(56);if (isEnabled()) {if (DBG) Log.d(TAG, "enable(): BT already enabled!");return true;}try {// 此处调用的是  IBluetoothManager.java的 enablereturn mManagerService.enable(ActivityThread.currentPackageName());} catch (RemoteException e) {Log.e(TAG, "", e);}return false;}

我们查看到 IBluetoothManager.java的实现类是BluetoothManagerService.java , BluetoothManagerService.java

class BluetoothManagerService extends IBluetoothManager.Stub {.....省略代码.....public boolean enable(String packageName) throws RemoteException {final int callingUid = Binder.getCallingUid();final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;.....省略代码.....// 权限检查.....省略代码.....synchronized(mReceiver) {mQuietEnableExternal = false;mEnableExternal = true;// waive WRITE_SECURE_SETTINGS permission checksendEnableMsg(false, packageName);}if (DBG) Slog.d(TAG, "enable returning");return true;}.....省略代码.....
}

我们继续查看可以看到调用的是 sendEnableMsg(boolean quietMode, String packageName) 方法.

 private void sendEnableMsg(boolean quietMode, String packageName) {mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,quietMode ? 1 : 0, 0));addActiveLog(packageName, true);}

在sendEnableMsg 方法中 发送了一个message消息 MESSAGE_ENABLE

 case MESSAGE_ENABLE:try {if (mBluetooth != null) {int state = mBluetooth.getState();if (state == BluetoothAdapter.STATE_BLE_ON) {//如果蓝牙已经打开调用 BluetoothAdapterService.java 开启profilemBluetooth.onLeServiceUp();//保存蓝牙的开关状态persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);break;}}}mQuietEnable = (msg.arg1 == 1);//如果没有蓝牙没有打开去打开蓝牙if (mBluetooth == null) {handleEnable(mQuietEnable);} else {if(state == BluetoothAdapter.STATE_TURNING_OFF || state == BluetoothAdapter.STATE_BLE_TURNING_OFF)waitForMonitoredOnOff(false, true);//重启蓝牙Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);mHandler.sendMessageDelayed(restartMsg,2 * SERVICE_RESTART_TIME_MS);}break;

在 MESSAGE_ENABLE 接收的消息中会先判断盘牙是否打开,如果已经打开 就调用mBluetooth.onLeServiceUp();去打开 Profile文件如果没有打开就调用handleEnable(mQuietEnable);去打开蓝牙. 咱们这里先不看 mBluetooth.onLeServiceUp(); 方法先查看handleEnable(mQuietEnable)

private void handleEnable(boolean quietMode) {if ((mBluetooth == null) && (!mBinding)) {//蓝牙打开超时记录Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);Intent i = new Intent(IBluetooth.class.getName());//此处我们查看到  mConnection 方法是链接状态的回调 if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,UserHandle.CURRENT)) {mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);} else {mBinding = true;}} }

其中mConnection 是链接的回调 BluetoothServiceConnection 就是 mConnection 类

在BluetoothServiceConnection 类中会发送   MESSAGE_BLUETOOTH_SERVICE_CONNECTED 消息并传递了一个 AdapterService对象.

 private class BluetoothServiceConnection implements ServiceConnection {public void onServiceConnected(ComponentName componentName, IBinder service) {String name = componentName.getClassName();if (DBG) Slog.d(TAG, "BluetoothServiceConnection: " + name);Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);if (name.equals("com.android.bluetooth.btservice.AdapterService")) {msg.arg1 = SERVICE_IBLUETOOTH;} msg.obj = service;mHandler.sendMessage(msg);}public void onServiceDisconnected(ComponentName componentName) {// Called if we unexpectedly disconnect.String name = componentName.getClassName();if (DBG) Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name);Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);if (name.equals("com.android.bluetooth.btservice.AdapterService")) {msg.arg1 = SERVICE_IBLUETOOTH;}mHandler.sendMessage(msg);}}

我们继续追踪  MESSAGE_BLUETOOTH_SERVICE_CONNECTED消息

case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:{IBinder service = (IBinder) msg.obj;mBinding = false;mBluetoothBinder = service;mBluetooth = IBluetooth.Stub.asInterface(service);//注册 CallBack 重要,后面的回调要使用try {mBluetooth.registerCallback(mBluetoothCallback);} catch (RemoteException re) {Slog.e(TAG, "Unable to register BluetoothCallback",re);}//Do enable requesttry {//打开蓝牙请求if (mQuietEnable == false) {if (!mBluetooth.enable()) {Slog.e(TAG,"IBluetooth.enable() returned false");}}}break;}

MESSAGE_BLUETOOTH_SERVICE_CONNECTED消息里面可以查看到 mBluetooth = IBluetooth.Stub.asInterface(service);获取的是 IBluetooth 对象 , 而AdapterService.java 内部类 AdapterServiceBinder  实现了 IBluetooth

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java
  private static class AdapterServiceBinder extends IBluetooth.Stub {private AdapterService mService;public AdapterService getService() {if (mService != null && mService.isAvailable()) {return mService;}return null;}public boolean enable() {........AdapterService service = getService();if (service == null) return false;return service.enable();}}

由上面可以看出 return service.enable();调用的是 AdapterService.java 中的方法 enable() 方法

 public synchronized boolean enable(boolean quietMode) {enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");debugLog("enable() - Enable called with quiet mode status =  " + mQuietmode);mQuietmode = quietMode;Message m = mAdapterStateMachine.obtainMessage(AdapterState.BLE_TURN_ON);mAdapterStateMachine.sendMessage(m);mBluetoothStartTime = System.currentTimeMillis();return true;}

发送的是 BLE_TURN_ON,

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java 接受了这个消息

case BLE_TURN_ON:notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON);//将蓝牙的状态转换成 mPendingCommandStatemPendingCommandState.setBleTurningOn(true);transitionTo(mPendingCommandState);sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY);adapterService.BleOnProcessStart();break;

将蓝牙的状态转换成 mPendingCommandState 调用 BleOnProcessStart 方法,也可以在supportedProfileServices  方法中去掉自己不想开启的ProfileService.

   void BleOnProcessStart() { //获取支持的profile 文件Class[] supportedProfileServices = Config.getSupportedProfiles();//Initialize data objectsfor (int i=0; i < supportedProfileServices.length;i++) {mProfileServicesState.put(supportedProfileServices[i].getName(),BluetoothAdapter.STATE_OFF);}mRemoteDevices.cleanup();mAdapterProperties.init(mRemoteDevices);mJniCallbacks.init(mBondStateMachine,mRemoteDevices);//Start Gatt service//调用 ProfileServicesetGattProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON);}

获取支持的ProfileService列表.

  private static final Class[] PROFILE_SERVICES = {HeadsetService.class,A2dpService.class,A2dpSinkService.class,HidService.class,HealthService.class,PanService.class,GattService.class,BluetoothMapService.class,HeadsetClientService.class,AvrcpControllerService.class,SapService.class,PbapClientService.class};

//发送  ACTION_SERVICE_STATE_CHANGED参数 每一个profile 都有 遍历开启 profile

  private void setGattProfileServiceState(Class[] services, int state) {for (int i=0; i <services.length;i++) {mProfileServicesState.put(serviceName,pendingState);Intent intent = new Intent(this,services[i]);intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED);intent.putExtra(BluetoothAdapter.EXTRA_STATE,state);startService(intent);return;}}}
  public int onStartCommand(Intent intent, int flags, int startId) {if (intent == null) {Log.d(mName, "Restarting profile service...");return PROFILE_SERVICE_MODE;} else {String action = intent.getStringExtra(AdapterService.EXTRA_ACTION);if (AdapterService.ACTION_SERVICE_STATE_CHANGED.equals(action)) {} else if (state == BluetoothAdapter.STATE_ON) {........省略代码......// 开启服务doStart(intent);}}return PROFILE_SERVICE_MODE;}

调用doStartService之后 我们可以看到调用了 notifyProfileServiceStateChanged 方法。

  private void doStart(Intent intent) {if (!mStartError) {// 开始调用 notifyProfileServiceStateChangednotifyProfileServiceStateChanged(BluetoothAdapter.STATE_ON);} }

继续查看notifyProfileServiceStateChanged 方法 ,里面又回到了AdapterServer 中的 onProfileServiceStateChanged方法

 protected void notifyProfileServiceStateChanged(int state) {//Notify adapter serviceAdapterService adapterService = AdapterService.getAdapterService();if (adapterService != null) {adapterService.onProfileServiceStateChanged(getClass().getName(), state);}}

发送MESSAGE_PROFILE_SERVICE_STATE_CHANGED 消息 给消息处理

 public void onProfileServiceStateChanged(String serviceName, int state) {Message m = mHandler.obtainMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED);m.obj=serviceName;m.arg1 = state;mHandler.sendMessage(m);}

在消息接收的地方查看到蓝牙的 processProfileServiceStateChanged 方法被调用,在processProfileServiceStateChanged 方法中发送了 BLE_STARTED 消息,而这个消息接受的地方是开起底层ProfileService的地方。

 case MESSAGE_PROFILE_SERVICE_STATE_CHANGED: {debugLog("handleMessage() - MESSAGE_PROFILE_SERVICE_STATE_CHANGED");processProfileServiceStateChanged((String) msg.obj, msg.arg1);}break;
   private void processProfileServiceStateChanged(String serviceName, int state) {if (isBleTurningOn) {if (serviceName.equals("com.android.bluetooth.gatt.GattService")) {debugLog("GattService is started");mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BLE_STARTED));return;}} }

/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java BLE_STARTED消息处理任务,通过 adapterService.enableNative(isGuest) 开启底层的profileService。

 case BLE_STARTED://开启底层服务if (!adapterService.enableNative(isGuest)) {errorLog("Error while turning Bluetooth on");notifyAdapterStateChange(BluetoothAdapter.STATE_OFF);transitionTo(mOffState);}break;

调用的是 AdapterService.java 中的native方法 ,根据包名和JNI 方法的名称我们可以推算出来调用的CPP的名称是 com_android_bluetooth_btservice_AdapterService.cpp

/*package*/ native boolean enableNative(boolean startRestricted);

在如下路径找到了 packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp 在enableNative中查看到 int ret = sBluetoothInterface->enable(isGuest == JNI_TRUE ? 1 : 0); 调用的是 sBluetoothInterface 中的enable方法

static jboolean enableNative(JNIEnv* env, jobject obj, jboolean isGuest) {ALOGV("%s:",__FUNCTION__);jboolean result = JNI_FALSE;if (!sBluetoothInterface) return result;int ret = sBluetoothInterface->enable(isGuest == JNI_TRUE ? 1 : 0);result = (ret == BT_STATUS_SUCCESS || ret == BT_STATUS_DONE) ? JNI_TRUE : JNI_FALSE;return result;
}

具体的实现在 bluetooth.c中。

/system/bt/btif/src/bluetooth.c
static int enable(bool start_restricted) {LOG_INFO(LOG_TAG, "%s: start restricted = %d", __func__, start_restricted);restricted_mode = start_restricted;if (!interface_ready())return BT_STATUS_NOT_READY;stack_manager_get_interface()->start_up_stack_async();return BT_STATUS_SUCCESS;
}

底层回调传递到上层的时候主要使用的是 btif_dm.c 中对消息的处理 BTA_DM_INQ_RES_EVT 消息:

system/bt/btif/src/btif_dm.c

static void btif_dm_search_devices_evt (UINT16 event, char *p_param)
{ ...省略代码.....case BTA_DM_INQ_RES_EVT:...省略代码...../* Callback to notify upper layer of device */HAL_CBACK(bt_hal_cbacks, device_found_cb,num_properties, properties);break;

/system/bt/btif/include/btif_common.h

define HAL_CBACK(P_CB, P_CBACK, ...) 方法 , HAL_CBACK就是一宏定义,就是调用结构体中对应的方法

extern bt_callbacks_t *bt_hal_cbacks;#define HAL_CBACK(P_CB, P_CBACK, ...)\if (P_CB && P_CB->P_CBACK) {            \BTIF_TRACE_API("HAL %s->%s", #P_CB, #P_CBACK); \P_CB->P_CBACK(__VA_ARGS__);         \}                                       \else {                                  \ASSERTC(0, "Callback is NULL", 0);  \}

bt_hal_cbacks 其实就是 蓝牙AdapterService中调用了initNative方法传入到底层的。看下jni中的initNative方法:

 @Overridepublic void onCreate() {super.onCreate();..........//调用底层方法initNative();........}

调用com_android_bluetooth_btservice_AdapterService.cpp init方法 将Callback传递到底层

static bool initNative(JNIEnv* env, jobject obj) {.......//调用com_android_bluetooth_btservice_AdapterService.cpp init方法 将Callback传递到底层// 再调用 bluetooth.c 的 init方法int ret = sBluetoothInterface->init(&sBluetoothCallbacks);.......
}

com_android_bluetooth_btservice_AdapterService.cpp  再调用 bluetooth.c 的 init方法

static int init(bt_callbacks_t *callbacks) {CallBack传递到底层bt_hal_cbacks = callbacks;stack_manager_get_interface()->init_stack();}

其实这里有两个地方有  bt_callbacks_t  我们可以对比看一下

1./hardware/libhardware/include/hardware/bluetooth.h

2. /packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp

bluetooth.h 中的 bt_callbacks_ttypedef struct {/** set to sizeof(bt_callbacks_t) */size_t size;adapter_state_changed_callback adapter_state_changed_cb;adapter_properties_callback adapter_properties_cb;remote_device_properties_callback remote_device_properties_cb;device_found_callback device_found_cb;discovery_state_changed_callback discovery_state_changed_cb;pin_request_callback pin_request_cb;ssp_request_callback ssp_request_cb;bond_state_changed_callback bond_state_changed_cb;acl_state_changed_callback acl_state_changed_cb;callback_thread_event thread_evt_cb;dut_mode_recv_callback dut_mode_recv_cb;le_test_mode_callback le_test_mode_cb;energy_info_callback energy_info_cb;
} bt_callbacks_t;
// com_android_bluetooth_btservice_AdapterService.cpp 中的 bt_callbacks_t
static bt_callbacks_t sBluetoothCallbacks = {sizeof(sBluetoothCallbacks),adapter_state_change_callback,adapter_properties_callback,remote_device_properties_callback,device_found_callback,discovery_state_changed_callback,pin_request_callback,ssp_request_callback,bond_state_changed_callback,acl_state_changed_callback,callback_thread_event,dut_mode_recv_callback,le_test_mode_recv_callback,energy_info_recv_callback
};
static bt_callbacks_t sBluetoothCallbacks = {sizeof(sBluetoothCallbacks),adapter_state_change_callback,adapter_properties_callback,remote_device_properties_callback,device_found_callback,discovery_state_changed_callback,pin_request_callback,ssp_request_callback,bond_state_changed_callback,acl_state_changed_callback,callback_thread_event,dut_mode_recv_callback,le_test_mode_recv_callback,energy_info_recv_callback
};

最后蓝牙驱动打开之后会通过  /system/bt/btif/src/btif_core.c 中的 btif_enable_bluetooth_evt(tBTA_STATUS status) 回调给应用

void btif_enable_bluetooth_evt(tBTA_STATUS status){// 省略代码HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, 1, &prop);
}

然后回调给 adapter_properties_callback:返回手机蓝牙设备的地址、名称、UUID

adapter_state_change_callback 回调 通过 C调用 Java的代码 callbackEnv->CallVoidMethod(sJniCallbacksObj, method_stateChangeCallback, (jint)status);  返回给应用中的也就是回调java层代码 JniCallback.java文件中stateChangeCallback方法。这时跳转到AdapterState.java中,执行stateChangeCallback()方法;发送了ENABLED_READY消息。根据以上分析,这时状态机还处于PendingCommandState,在该状态下处理ENABLED_READY消息,

 case ENABLED_READY:removeMessages(ENABLE_TIMEOUT);mPendingCommandState.setBleTurningOn(false);transitionTo(mBleOnState);notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON);break;

做下面两个动作:状态切换到mOnState;更新adapterProperties中的蓝牙状态信息;通知蓝牙状态变为打开。具体看下notifyAdapterStateChange方法。主要是调用了adapterService类的方法。

private void notifyAdapterStateChange(int newState) {AdapterService adapterService = mAdapterService;AdapterProperties adapterProperties = mAdapterProperties;if ((adapterService == null) || (adapterProperties == null)) {errorLog("notifyAdapterStateChange after cleanup:" + newState);return;}int oldState = adapterProperties.getState();adapterProperties.setState(newState);infoLog("Bluetooth adapter state changed: " + oldState + "-> " + newState);adapterService.updateAdapterState(oldState, newState);}

adapterService.updateAdapterState(oldState, newState); 
来到adapterService类。

  void updateAdapterState(int prevState, int newState){if (mCallbacks !=null) {int n=mCallbacks.beginBroadcast();debugLog("updateAdapterState() - Broadcasting state to " + n + " receivers.");for (int i=0; i <n;i++) {try {
// 完成回调 发送广播给调用者                    mCallbacks.getBroadcastItem(i).onBluetoothStateChange(prevState,newState);}  catch (RemoteException e) {debugLog("updateAdapterState() - Callback #" + i + " failed ("  + e + ")");}}mCallbacks.finishBroadcast();}}

之前在打开蓝牙操作初期,在BluetoothManagerService中注册了回调方法,因此又跳转到framework中,执行回调方法。蓝牙打开从framework公共接口开始调用enable方法,执行到bluetooth.apk中,在该应用中通过jni注册回调方法和调用hal层打开蓝牙方法,在驱动层完成蓝牙上电等操作后,通过hal-jni回调到应用层中,应用通过aidl回调通知framework蓝牙状态变化,framework发送广播通知大家蓝牙打开。

Android 蓝牙启动流程(以及设置蓝牙为作为sink模式 接收端模式)相关推荐

  1. 【Android 逆向】加壳的 Android 应用启动流程 | 使用反射替换 LoadedApk 中的类加载器流程

    文章目录 一.加壳的 Android 应用启动流程 二.使用反射替换 LoadedApk 中的类加载器流程 一.加壳的 Android 应用启动流程 加壳的 Android 应用启动流程 : 加壳的 ...

  2. Android开机启动流程

    Android开机启动流程 一.APPS PBL(Application primary boot loader:主引导加载程序) 二.XBL(Extensible boot loader:可扩展引导 ...

  3. 【SemiDrive源码分析】【X9芯片启动流程】30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一)

    [SemiDrive源码分析][X9芯片启动流程]30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一) 一.Android Kernel 启动流程分析 ...

  4. Android开机启动流程简析

    Android开机启动流程简析 (一) 文章目录 Android开机启动流程简析 (一) 前言 一.开机启动的流程概述 二.Android的启动过程分析 (1).总体流程 init简述 Zygote简 ...

  5. Android -- Wifi启动流程分析

    Android -- Wifi启动流程分析 Android网络各个模式中,Wifi应该是目前最常用的一种网络方式了:下面就简单介绍下Android中Wifi的启动流程. 当我在Setting菜单里点击 ...

  6. android zygote启动流程,Android zygote启动流程详解

    对zygote的理解 在Android系统中,zygote是一个native进程,是所有应用进程的父进程.而zygote则是Linux系统用户空间的第一个进程--init进程,通过fork的方式创建并 ...

  7. 【Android 逆向】Android 进程简介 ( Android 应用启动流程 )

    文章目录 前言 一.Android 进程 二.Android 应用启动流程 前言 参考 [Android 逆向]Android 系统文件分析 ( /proc/pid 进程号对应进程目录 | oom_a ...

  8. 【SemiDrive源码分析】【X9芯片启动流程】27 - AP1 Android Preloader启动流程分析(加载atf、tos、bootloader镜像后进入BL31环境)

    [SemiDrive源码分析][X9芯片启动流程]27 - AP1 Android Preloader启动流程分析(加载atf.tos.bootloader镜像后进入BL31环境) 一.Android ...

  9. Android 安卓启动流程

    安卓启动名词缩写笔记: QRD(QualcommReferenceDesign):高通参考设计 AOP(Alwaysonprocessor):实时响应处理器 SP(SecureProcessor):安 ...

最新文章

  1. 【全网之最】用JavaScript写一个最简短的语句实现从A数组中去除B数组中相同元素
  2. 对于mysql存储过程感想_存储过程学习心得
  3. php运行ecshop,ecshop2.x代码执行
  4. python填写excel-Python向excel中写入数据的方法
  5. 思科:2022年视频将占移动通信流量79%
  6. JAVA 数组元素的反转
  7. [转载] WSDL2Java详细使用说明【官方最全说明】
  8. java实现从头部及尾部删除指定长度字符
  9. C#学习笔记_12_枚举结构体
  10. 数据库-windows上安装mysql
  11. Ubuntu 20.04 锐捷客户端安装记录
  12. 【项目难点】电商后台管理系统
  13. 神奇的泡泡java游戏,抖音挤泡泡游戏叫什么名字 抖音上很火的减压游戏介绍
  14. 爬虫-东北林业大学校内-中国[哈尔滨]森林博物馆-爬取所有馆藏蝴蝶图片
  15. 教学教法改革效果评估的4种方法
  16. 【每日一题】打卡 12
  17. PHP版本更新功能实现,技术分享:最低PHP版本更新操作 | Wopus
  18. 数据库--数据备份与恢复
  19. 从游戏中学习产品设计2:消费篇
  20. 苹果CMS插件-苹果CMS必备插件

热门文章

  1. queueing 优化_简单聊聊网页的资源加载优化
  2. java 自定义注解_两步实现Java自定义注解
  3. 线程中CreateEvent和SetEvent及WaitForSingleObject的用法
  4. sizebox模型下载_css 盒模型、box-sizing 学习笔记
  5. GMS(cts、gsi、vts、gts、ctsv)问题总结
  6. python 第一课
  7. Linux系统 shell基础(二)
  8. JSR-303 Bean Validation 介绍及 Spring MVC 服务端验证最佳实践
  9. jQuery中读取json文件示例代码
  10. Logstash inputs配置