解决在Setting界面中打开bluetooth 导致setting界面以外退出问题的过程

     BluetoothEnabler.java  +187
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {  
       // Show toast message if Bluetooth is not allowed in airplane mode  
       if (isChecked &&  
               !WirelessSettings.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {  
           Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();  
           // Reset switch to off  
           buttonView.setChecked(false);            
       }  

       if (mLocalAdapter != null) {  
           mLocalAdapter.setBluetoothEnabled(isChecked);  
       }  
       mSwitch.setEnabled(false);  
   }  

继续看setBluetoothEnabled()方法做什么了,很明显mLocalAdapter(LocalBluetoothAdapter )只是个过渡,里面的 mAdapter(BluetoothAdapter)才是真正的主角

       LocalBluetoothAdapter.java +205
public void setBluetoothEnabled(boolean enabled) {  
    boolean success = enabled   ? mAdapter.enable() : mAdapter.disable();  

    if (success) {  
        setBluetoothStateInt(enabled  
            ? BluetoothAdapter.STATE_TURNING_ON  
            : BluetoothAdapter.STATE_TURNING_OFF);  
    } else {  
       .........  
    }  
}  

在BluetoothAdapter.java里可以看到一个单例模式的应用,主要提供给其它程序调用蓝牙的一些方法用的,外部程序想调用蓝牙的方法就要先用这个。再继续追就是frameworks层,底层如何实现打开蓝牙的过程,我们在这这个方向不研究。

触发蓝牙搜索的条件形式上有两种,一是在蓝牙设置界面开启蓝牙会直接开始搜索,另一个是先打开蓝牙开关在进入蓝牙设置界面也会触发搜索,也可能还有其它触发方式,但最后都要来到BluetoothSettngs.java的startScanning(),我们分析的起点也从这里开始,起步代码如下
BluetoothSettings.java +282

switch (bluetoothState) {                                                                                                                            case BluetoothAdapter.STATE_ON:
............         
if (!mInitialScanStarted) {                                                                                              

   startScanning();

  }
...........

  private void startScanning() {
  ...........

mLocalManager.getCachedDeviceManager().clearNonBondedDevices();
258         mAvailableDevicesCategory.removeAll();
259         mInitialScanStarted = true;
260         mLocalAdapter.startScanning(true); //!!!!!                                                                                              
262     }

其实在这里蓝牙搜索和打开流程是结构上是一致的,利用LocalBluetoothAdapter.java过渡到BluetoothAdapter.java再跳转至AdapterService.java要稍微留意下的是在这个过渡中startScaning()方法变成了startDiscovery()方法,看下代码:
LocalBluetoothAdapter.java +141

void startScanning(boolean force) {  
if (!mAdapter.isDiscovering()) {  
     if (!force) {  
         // Don't scan more than frequently than SCAN_EXPIRATION_MS,  
         // unless forced  
         if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {  
             return;  
         }  
         // If we are playing music, don't scan unless forced.  
         A2dpProfile a2dp = mProfileManager.getA2dpProfile();  
         if (a2dp != null && a2dp.isA2dpPlaying()) {  
             return;  
         }  
     }  
//这里才是我们最关注的,前面限制条件关注一下就行了  
     if (mAdapter.startDiscovery()) {  
         mLastScan = System.currentTimeMillis();  
     }  
}  

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java +746

public boolean startDiscovery() {  
    .............................  
    AdapterService service = getService();  
    if (service == null) return false;  
    return service.startDiscovery();  
}  

BluetoothAdapter.java的那一段,路径 /frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java +840

 840     public boolean startDiscovery() {
   ...                                                                                                                      
 843     synchronized(mManagerCallback) {
 844      if (mService != null) 
 return   mService.startDiscovery(); !!!!!
 845             }
 846    .....  
 848     }

1221 boolean startDiscovery() {  
 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,  
            "Need BLUETOOTH ADMIN permission");  

    return startDiscoveryNative();  
}  

这个service代码写得很明白AdapterService,转了一圈从framework又回到packages了。
和打开蓝牙根本就是一个套路,上面的流程略过一小步,很简单的不写了,下面要怎么走,估计大家也都猜到了,JNI应该出场了,
路径:/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp +820

static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {                                                     
    ALOGV("%s:",__FUNCTION__);                                  

    jboolean result = JNI_FALSE;                                
    if (!sBluetoothInterface) return result;                    

    int ret = sBluetoothInterface->start_discovery();           
    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE :    JNI_FALSE;  
    return result;                                              
} 

路径:/external/bluetooth/bluedroid/btif/src/bluetooth.c +250

static int start_discovery(void)  
{  
    /* sanity check */  
    if (interface_ready() == FALSE)  
        return BT_STATUS_NOT_READY;  

    return btif_dm_start_discovery();  
} 

下面代码直接跳转就可以找到,路径external/bluetooth/bluedroid/btif/src/btif_dm.c +2148

bt_status_t btif_dm_start_discovery(void)                                    
{                                                                            
    tBTA_DM_INQ inq_params;                                                  
    tBTA_SERVICE_MASK services = 0;                                          

    BTIF_TRACE_EVENT1("%s", __FUNCTION__);                                   
    /* TODO: Do we need to handle multiple inquiries at the same time? */    

    /* Set inquiry params and call API */                                    
#if (BLE_INCLUDED == TRUE)                                                   
    inq_params.mode = BTA_DM_GENERAL_INQUIRY|BTA_BLE_GENERAL_INQUIRY;        
#else                                                                        
    inq_params.mode = BTA_DM_GENERAL_INQUIRY;                                
#endif                                                                       
    inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;                  

    inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;                  
    inq_params.report_dup = TRUE;                                            

    inq_params.filter_type = BTA_DM_INQ_CLR;                                 
    /* TODO: Filter device by BDA needs to be implemented here */            

    /* Will be enabled to TRUE once inquiry busy level has been received */  
    btif_dm_inquiry_in_progress = FALSE;                                     
    /* find nearby devices */                                                   BTA_DmSearch(&inq_params, services, bte_search_devices_evt);             

    return BT_STATUS_SUCCESS;                                                
}   

BTA_DmSearch()方法是看起来是要搜索了,不过里面这个家伙bte_search_devices_evt才是真正干活的主力,所以我们先看它,在这个函数里

static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)                                                                      {                                                                                                                    
       UINT16 param_len = 0;                                                                                           

       if (p_data)                                                                                                      
           param_len += sizeof(tBTA_DM_SEARCH);                                                                         
       /* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */  
       switch (event)                                                                                                   
       {                                                                                                                
           case BTA_DM_INQ_RES_EVT:                                                                                     
           {                                                                                                            
               if (p_data->inq_res.p_eir)                                                                               
                   param_len += HCI_EXT_INQ_RESPONSE_LEN;                                                               
           }                                                                                                            
           break;                                                                                                              
          ..............................                                                                                                
       }                                                                                                                
       BTIF_TRACE_DEBUG3("%s event=%s param_len=%d", __FUNCTION__, dump_dm_search_event(event), param_len);             

       /* if remote name is available in EIR, set teh flag so that stack doesnt trigger RNR */                          
       if (event == BTA_DM_INQ_RES_EVT)                                                                                 
           p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);                          

       btif_transfer_context (btif_dm_search_devices_evt , (UINT16) event, (void *)p_data, param_len,                   
           (param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);                                       
   } 

上面的这个函数里又有这个bte_search_devices_evt,在它里我们能看一个 HAL_CBACK,这是要往回发消息了,看下这个函数的全貌,说是全貌,不过还是只贴出一个case分支,太长了,大家还是自行还源码吧。到这里已经可以知道扫描到蓝牙设备的mac地址和设备名,那个bdcpy函数就是在解析mac地址,有了这些,蓝牙搜索是到应该在界面展示成果的时候了,开始回调。

static void btif_dm_search_devices_evt (UINT16 event, char *p_param)  

   tBTA_DM_SEARCH *p_search_data;  
   BTIF_TRACE_EVENT2("%s event=%s", __FUNCTION__, dump_dm_search_event(event));  

   switch (event)  
   {  
       case BTA_DM_DISC_RES_EVT:  
       {  
           p_search_data = (tBTA_DM_SEARCH *)p_param;  
           /* Remote name update */  
           if (strlen((const char *) p_search_data->disc_res.bd_name))  
           {  
               bt_property_t properties[1];  
               bt_bdaddr_t bdaddr;  
               bt_status_t status;  

               properties[0].type = BT_PROPERTY_BDNAME;  
               properties[0].val = p_search_data->disc_res.bd_name;  
               properties[0].len = strlen((char *)p_search_data->disc_res.bd_name);  
               bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr);  

               status = btif_storage_set_remote_device_property(&bdaddr, &properties[0]);  
               ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device property", status);  
               HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,  
                                status, &bdaddr, 1, properties);  
           }  
           /* TODO: Services? */  
       }  
       break;  

当然回过头我们还要看下那个BTA_DmSearch(),看它的实现,更应该是起消息发送的作用,代码在/external/bluetooth/bluedroid/bta/dm/bta_dm_api.c, +2196 这个函数具体流程并没有看多少,当工具方法看了,有时间看看还是没坏处的。

void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)  
{  tBTA_DM_API_SEARCH    *p_msg;  
    if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)  
    {  
        memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));  

        p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;  
        memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));  
        p_msg->services = services;  
        p_msg->p_cback = p_cback;  
        p_msg->rs_res  = BTA_DM_RS_NONE;  
        bta_sys_sendmsg(p_msg);  
    }  
}  

看了上面方法后我们 要回去了看看,代码通过JNI下来的,回去也是看JNI的回调方法,packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp +698

method_deviceFoundCallback = env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V"); 

deviceFoundCallback方法最后会来java层的 /packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java +327

void deviceFoundCallback(byte[] address) {  
       // The device properties are already registered - we can send the intent  
       // now  
       BluetoothDevice device = getDevice(address);  
       debugLog("deviceFoundCallback: Remote Address is:" + device);  
       DeviceProperties deviceProp = getDeviceProperties(device);  
       if (deviceProp == null) {  
           errorLog("Device Properties is null for Device:" + device);  
           return;  
       }  
     Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);  

    intent.putExtra(BluetoothDevice.EXTRA_DEVICE,device) 

    intent.putExtra(BluetoothDevice.EXTRA_CLASS,  new BluetoothClass(Integer.valueOf(deviceProp.mBluetoothClass)));  
       intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);  
       intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);  

      mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);  
   } 

到这里就是给界面发广播,应用层收到广播显示出来,通过这个handle,这个handle可以在BluetoothEventManager.java +90 +144的构造函数里找到

addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());  


    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {  
    @Override  
    public void onReceive(Context context, Intent intent) {  
        String action = intent.getAction();  
        BluetoothDevice device = intent  
            .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);  
   Handler handler = mHandlerMap.get(action);  
       if (handler != null) {  
         handler.onReceive(context, intent, device);  
        }  
    }  
};  

“这里handle对应要看DeviceFoundHandler, +207 也就是下面贴出来的代码,

 private class DeviceFoundHandler implements Handler {  
    public void onReceive(Context context, Intent intent,  
            BluetoothDevice device) {  
       ........................  
        // TODO Pick up UUID. They should be available for 2.1 devices.  
        // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.  
        CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);  
        if (cachedDevice == null) {  
            cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);  
            Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "  
                    + cachedDevice);  
            // callback to UI to create Preference for new device  
            dispatchDeviceAdded(cachedDevice);  
        }  
      ......................  
    }  
}
.........
234   private void dispatchDeviceAdded(CachedBluetoothDevice
cachedDevice) {
235    synchronized (mCallbacks) {
236  for (BluetoothCallback callback : mCallbacks)
      {
               callback.onDeviceAdded(cachedDevice);                                                                                    
238             }
239         }
240     }

在if语句中dispatchDeviceAdded()向界面分发消息,最后处理消息的地方在这里,搜索onDeviceAdded,已经到settings应用里了
/packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +160

public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {                   
   if (mDevicePreferenceMap.get(cachedDevice) != null) {                          
       return;                                                                    
   }                                                                              
                                                                                // Prevent updates while the list shows one of the state messages              
   if (mLocalAdapter.getBluetoothState() != BluetoothAdapter.STATE_ON) return;    

   if (mFilter.matches(cachedDevice.getDevice())) {                               
       createDevicePreference(cachedDevice);                                      
   }                                                                              
}     

第二条路线
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java +621

611     void discoveryStateChangeCallback(int state) {                                                                                       
612         infoLog("Callback:discoveryStateChangeCallback with state:" + state);
613         synchronized (mObject) {
614             Intent intent;
615             if (state == AbstractionLayer.BT_DISCOVERY_STOPPED) {
616                 mDiscovering = false;
617                 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
618                 mService.sendBroadcast(intent, mService.BLUETOOTH_PERM);
619             } else if (state == AbstractionLayer.BT_DISCOVERY_STARTED) {
620                 mDiscovering = true;
621                 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
622                 mService.sendBroadcast(intent, mService.BLUETOOTH_PERM);
623             }
624         }
625     }

sendBroadcast发送intent,action为BluetoothAdapter.ACTION_DISCOVERY_STARTED

packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothEventManager.java +88

 59     void addHandler(String action, Handler handler) {                                                                                    
 60         mHandlerMap.put(action, handler);
 61         mAdapterIntentFilter.addAction(action);
 62     }
 74     BluetoothEventManager(LocalBluetoothAdapter adapter,
 75             CachedBluetoothDeviceManager deviceManager, Context context) {
 76         mLocalAdapter = adapter;
 77         mDeviceManager = deviceManager;
 78         mAdapterIntentFilter = new IntentFilter();
 79         mProfileIntentFilter = new IntentFilter();
 80         mHandlerMap = new HashMap<String, Handler>();
 81         mContext = context;
 82 
 83         // Bluetooth on/off broadcasts
 84         addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
 85 
 86         // Discovery broadcasts
 87         Log.e(TAG, "broadcasts6666666666666666666666666");
 88         addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
 89         addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
 90         addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
 91         addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
 92         addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
 93 
 94         Log.e(TAG, "broadcasts6666666666666666666666666");
 95         // Pairing broadcasts
 96         addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
 97         addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());                                                   
 98 
 99         // Fine-grained state broadcasts
100         addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
101         addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
102 
103         // Dock event broadcasts
104         addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
105 
106         mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);
107     }
108 
109     void registerProfileIntentReceiver() {
110         mContext.registerReceiver(mBroadcastReceiver, mProfileIntentFilter);
111     }

指定广播mProfileIntentFilter(action),和mBroadcastReceiver。

144     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
145         @Override
146         public void onReceive(Context context, Intent intent) {
147             Log.e(TAG, "shinan.com2-start-1");
148             String action = intent.getAction();
149             BluetoothDevice device = intent
150                     .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
151 
152             Handler handler = mHandlerMap.get(action);
153             if (handler != null) {
154                 Log.e(TAG, action);
155                 
156                 Log.e(TAG, "-----------------" + context);
157                 Log.e(TAG, "-----------------" + intent);
158                 Log.e(TAG, "-----------------" + device);
159             Log.e(TAG, "shinan.com2-start-2");
160            // if(device != null)
161                handler.onReceive(context, intent, device);
162 
163             Log.e(TAG, "shinan.com2-start-3");
164             }
165         }
166     };  

最后执行handler.onReceive(context, intent, device);
实现onReceive的方法有多个,

168     private class AdapterStateChangedHandler implements Handler {
169         public void onReceive(Context context, Intent intent,
170                 BluetoothDevice device) {
171             int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
172                                     BluetoothAdapter.ERROR);
173             // update local profiles and get paired devices
174             mLocalAdapter.setBluetoothStateInt(state);
175             // send callback to update UI and possibly start scanning
176             synchronized (mCallbacks) {
177                 for (BluetoothCallback callback : mCallbacks) {
178                     callback.onBluetoothStateChanged(state);
179                 }
180             }
181             // Inform CachedDeviceManager that the adapter state has changed
182             mDeviceManager.onBluetoothStateChanged(state);
183         }
184     }    
186     private class ScanningStateChangedHandler implements Handler {
187         private final boolean mStarted;
188 
189         ScanningStateChangedHandler(boolean started) {
190             mStarted = started;
191         }
192         public void onReceive(Context context, Intent intent,
193                 BluetoothDevice device) {
194             synchronized (mCallbacks) {
195                 for (BluetoothCallback callback : mCallbacks) {
196                     callback.onScanningStateChanged(mStarted);
197                     Log.e(TAG, "*******************************************" + callback);
198                 }
199             }
200             Log.e(TAG, "++++++++++++++++++++++++++++++++++++++++++++++" + mStarted );
201             mDeviceManager.onScanningStateChanged(mStarted);
202             LocalBluetoothPreferences.persistDiscoveringTimestamp(context);
203             Log.e(TAG, "++++++++++++++++++++++++++++++++++++++++++++++" + context );
204         }
205     }   

.onScanningStateChanged(mStarted)的方法实现有两种分别如下:
第一种 201行的mDeviceManager.onScanningStateChanged(mStarted);方法定义之处在packages/apps/Settings/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java +124

124     public synchronized void onScanningStateChanged(boolean started) {
125         if (!started) return;
126 
127         // If starting a new scan, clear old visibility
128         // Iterate in reverse order since devices may be removed.
129         for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
130             CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
131             cachedDevice.setVisible(false);
132 
133         Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%====3");                                                                 
134         }
135     }

第二种 196行的callback.onScanningStateChanged(mStarted); 的方法定义之处在packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothSettings.java +391

391     public void onScanningStateChanged(boolean started) {
392         super.onScanningStateChanged(started);
393         // Update options' enabled state
394         Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%bluetoothsetting");
395         if (getActivity() != null) {
396 
397         Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%bluetoothsetting");
398             getActivity().invalidateOptionsMenu();
399 
400         Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%bluetoothsetting");
401         }
402     }

上面其中的392行super.onScanningStateChanged(started)
定义之处在packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +208

208     public void onScanningStateChanged(boolean started) {
209         
210         Log.e(TAG, "#############################snmu######" + snmu_3);
211         Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%====4");
212         updateProgressUi(started);
213         Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=====4");
214     }  

开关打开后的操作:
BluetoothSettings.java +282 +260
LocalBluetoothAdapter.java +141
frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java +840

核心问题所在路径
packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +207

packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothEventManager.java +88,89

packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +156

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java +273

packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothSettings.java +287 +391 +328

本次任务耗时半月完成,第一次接触安卓,进度比较慢,思路不是那么清晰,

Android中bluetooth的架构
这里写图片描述
这里写图片描述
Settings App:用于构造设置中的UI。就是我们在手机打开设置时所看到的打开/关闭蓝牙的UI操作。

Bluetooth App:这一块在图中没有画出来,他并不直接体现在UI上,可以理解为一个后台运行的apk。包括了蓝牙文件发送(OPP)和电话薄传输(PBAP)两个部分。

在中间Framework层,主要实现了各种API,这些API最终都是要通过jni层调入到下面来具体实现的。当然,他们还承担着接受底层消息的重任,这些消息也是要最终反馈到UI层的。

kernel层之下就是我们的bluetooth的芯片接口driver,
kernel\drivers\bluetoothBluetooth
external\bluetooth\bluedroid BlueZ (应用空间协议),官方蓝牙协议栈。

首先很容易就会发现一个和UI上很相关的代码位于packages/apps/Settings/src/com/android/settings/目录下。基本而言,各种UI上的处理都是在这个目录的bluetooth文件夹下实现的。所以,一般对蓝牙的打开/关闭,搜索,配对等等的按钮的处理,都是从这里开始的,这里也将是我们阅读代码的第一步。

我们都了解Android的系统架构,app层一般都调用到framework去进行进一步的实现,蓝牙也不例外。在framework层,蓝牙的代码主要位于frameworks/base/core/java/android/bluetooth目录下面。这个文件基本属于API的类型,向上层UI提供了所需要的API,换句话说,上层的UI比如Settings那边的代码都是通过这个文件夹下的文件进行调用的。然而,这个文件夹也只是client端的代码而已,它的servier端的代码大部分位于
frameworks/base/core/java/android/server目录下面,这里就是直接建立于jni层之上的代码了,负责向jni的调用,同时也负责从jni层接收相应的消息,从而反馈到UI层。

Framework层之下就是jni层了,这个比较简单,都位于frameworks/base/core/jni这个目录下面。Android4.0的代码还是基于bluez的,所以,这里也就是通过dbus和bluez进行通信了。说到bluez,它的代码基本位于external/bluetooth/bluez目录下。应该说是一个比较好的蓝牙stack了。他在tools目录下还提供了一些tool,其中hciattach和hcidump两个tool是非常有用的,前者在bluetooth的初始化中占有极为重要的地位,后者则在日常的debug过程中不可或缺。

Jni层之下就是kernel层了,相对而言,kernel层的代码还是蛮好找的,一份为stack,位于kernel/net/bluetooth目录下面,HCI,L2CAP,RFCOMM等的代码实现基本都是在这里面了。另一份则位于kernel/driver/bluetooth目录下面,各家蓝牙方案的driver都位于这里。

.常用类和名词解释:
\packages\apps\Settings\src\com\android\settings\bluetooth 目录下
BluetoothEnabler.java 界面上蓝牙开启、关闭的开关就是它了,
BluetoothSettings.java 主界面,用于管理配对和连接设备
LocalBluetoothManager.java 提供了蓝牙API上的简单调用接口,这里只是开始。
CachedBluetoothDevice.java 描述蓝牙设备的类,对BluetoothDevice的再封装
BluetoothPairingDialog.java 那个配对提示的对话框

这里写图片描述
这个界面的实现是在这个文件中:/packages/apps/Settings/res/xml/

bluetoothEventManager是用来管理api那边传过来的broadcast和callback,他会根据各个broadcast进行最终的分配,

BluetoothEventManager(LocalBluetoothAdapter adapter,  
           CachedBluetoothDeviceManager deviceManager, Context context) {  
       mLocalAdapter = adapter;  
       mDeviceManager = deviceManager;  
       mAdapterIntentFilter = new IntentFilter();  
       mProfileIntentFilter = new IntentFilter();  
       mHandlerMap = new HashMap<String, Handler>();  
       mContext = context;  

       // Bluetooth on/off broadcasts  
    // ACTION_STATE_CHANGED,在蓝牙的on和off的时候会发出  
       addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());  
    //这两个是扫描的broadcast,分别表示开始扫描和停止扫描  
       // Discovery broadcasts  
       addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));  
       addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));  
    //这是扫描到设备和设备消失的broadcast  
       addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());  
       addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());  
    //这个是设备名字改变的action  
       addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());  

       // Pairing broadcasts  
    //这个是设备配对状态改变的action,比如正在配对,已经配对之类的  
       addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());  
    //取消配对的handler  
       addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());  

       // Fine-grained state broadcasts  
    //CLASS和UUID改变的action  
       addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());  
       addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());  

       // Dock event broadcasts  
    //dock的event  
       addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());  
    //注册对这些action处理的receiver  
       mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);  
   }  

BluetoothEventManager—用于管理从framework的bluetooth api那边上来的broadcast和callback,并把这些反馈到对应的class中去。

在打开Settings的时候,我们看到的ui上蓝牙相关的内容已经全部讲解完毕了。回顾一下,总得来说,就是首先有一个header的列表,然后在onBuildHeaders中会把这个列表加载进来,然后根据每个header不同的类型决定是否加入一些别的元素,比如按钮之类的。然后具体关联到bluetooth中去,根据bluetooth当时处于的状态显示对应的按钮状况,如实是否处于打开之类的。大概的流程就是这样了

这里写图片描述
路径 packages/apps/Settings/AndroidManifest.xml +326
先来看一下xml中fragment的设置:

android:fragment="com.android.settings.bluetooth.BluetoothSettings" 

所以,很明确,我们要去看BluetoothSettings了。

public final class BluetoothSettings extends DeviceListPreferenceFragment  

可以很明确地看到BluetoothSettings是扩展DeviceListPreferenceFragment,而BluetoothSettings中并没有重写onCreate()方法,所以,我们去DeviceListPreferenceFragment看看。

2————————————————————–
logcat 捕捉的错误信息

--------- beginning of crash
528 F/libc    ( 1400): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x10 in tid 1400 (ndroid.settings)
529 I/DEBUG   (   95): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
530 I/DEBUG   (   95): Build fingerprint: 'Ingenic/dorado/dorado:5.0/LRX21M/snmu02281416:userdebug/test-keys'
531 I/DEBUG   (   95): Revision: '0'
532 I/DEBUG   (   95): ABI: 'mips'
533 I/DEBUG   (   95): pid: 1400, tid: 1400, name: ndroid.settings  >>> com.android.settings <<<
534 I/DEBUG   (   95): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x10
535 I/DEBUG   (   95):  zr 00000000  at 00000001  v0 00001988  v1 00000000
536 I/DEBUG   (   95):  a0 2fcd6c30  a1 00000662  a2 00000000  a3 7f86dad0
537 I/DEBUG   (   95):  t0 7f800001  t1 00000000  t2 73f69300  t3 00000001
538 I/DEBUG   (   95):  t4 54442d18  t5 3ff921fb  t6 54442d18  t7 400921fb
539 I/DEBUG   (   95):  s0 73f07800  s1 73efea4c  s2 7f86fe8c  s3 00000004
540 I/DEBUG   (   95):  s4 2f7ebb10  s5 7f86fe10  s6 7f86fe00  s7 0000b7a4
541 I/DEBUG   (   95):  t8 00000014  t9 73e041e8  k0 00000000  k1 00000000
542 I/DEBUG   (   95):  gp 73f018c0  sp 7f86da58  s8 7f86fd70  ra 73a76b84
543 I/DEBUG   (   95):  hi 00000000  lo 00000900 bva 00000010 epc 73e04244
544 I/DEBUG   (   95): 
545 I/DEBUG   (   95): backtrace:
546 I/DEBUG   (   95):     #00 pc 00455244  /system/lib/libart.so (artAllocObjectFromCodeRosAlloc+92)
547 I/DEBUG   (   95):     #01 pc 000c7b84  /system/lib/libart.so (art_quick_alloc_object_rosalloc+68)
548 I/DEBUG   (   95):     #02 pc 0173884c  /data/dalvik-cache/mips/system@framework@boot.oat
549 I/DEBUG   (   95): 
550 I/DEBUG   (   95): Tombstone written to: /data/tombstones/tombstone_03

mips-linux-gnu-addr2line -f -e ./out/target/product/dorado/system/lib/libart.so 0x000c7b84 (输出日志中最上面的pc值,可以回溯最终函数调用顺序)
cd art grep -rn“artAllocObjectFromCode”.

./runtime/entrypoints/quick/quick_alloc_entrypoints.cc:29:extern "C" mirror::Object* artAllocObjectFromCode ##suffix##suffix2
vim quick_alloc_entrypoints.cc +29
确定是这个函数 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值