Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android源碼分析]bluez中adapter初始化分析

[Android源碼分析]bluez中adapter初始化分析

編輯:關於Android編程

作為一個程序員,咋廢話就不多說了,直接看代碼吧,哈哈~~       2)adapter的初始化   [cpp]   gboolean adapter_init(struct btd_adapter *adapter)   {       int err;          /* adapter_ops makes sure that newly registered adapters always       * start off as powered */       //置up位,為什麼不放到最後在置位啊       adapter->up = TRUE;       //讀bdaddr,這個就是得到dev的bdaddr到adapter->bdaddr       adapter_ops->read_bdaddr(adapter->dev_id, &adapter->bdaddr);       //和BDADDR_ANY比較一下,若是一樣就是有問題啦。       if (bacmp(&adapter->bdaddr, BDADDR_ANY) == 0) {           error("No address available for hci%d", adapter->dev_id);           return FALSE;       }       //同樣的時候拷貝dev的features到adapter的features中       err = adapter_ops->read_local_features(adapter->dev_id,                               adapter->features);       if (err < 0) {           error("Can't read features for hci%d: %s (%d)",                       adapter->dev_id, strerror(-err), -err);           return FALSE;       }       //對應的config文件下,看是否有name,顯然是沒有的,所以會進入if中       if (read_local_name(&adapter->bdaddr, adapter->name) < 0)   //adapter->name應該是null了,main_opts.name就是main.conf中的內容了,是%m。這裡就是初始化adapter->name的值了。讀取的是ro.product.model的值,他在buildinfo.sh定義為PRODUCT_MODEL,而PRODUCT_MODEL就是對應的base.mk中定義的,所以,我們可以在這裡改變名字。就是我們見到的8825gc,具體見2-1.           expand_name(adapter->name, MAX_NAME_LENGTH, main_opts.name,                               adapter->dev_id);   //是否支持gatt,顯然目前我們並不支持       if (main_opts.attrib_server)           attrib_gap_set(GATT_CHARAC_DEVICE_NAME,               (const uint8_t *) adapter->name, strlen(adapter->name));   //初始化service list,就是把開始的那些service record和adapter這邊關聯起來。見2-2       sdp_init_services_list(&adapter->bdaddr);   //就是加載那些plugin的adpater driver,見2-3分析       load_drivers(adapter);   //清除block列表       clear_blocked(adapter);   //加載device,就是創建一系列的文件,見2-4分析       load_devices(adapter);       /* Set pairable mode */       //讀config文件下的pairable的值,若是沒有讀到就設為true,否則就是讀到的值       if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)           adapter->pairable = TRUE;          /* retrieve the active connections: address the scenario where       * the are active connections before the daemon've started */        //得到active的connection       load_connections(adapter);       //initialized設為true       adapter->initialized = TRUE;          return TRUE;   }     2-1 expand_name分析   expand_name就是擴展名字了。這裡ANDROID_EXPAND_NAME是必然會定義了的   [cpp]   static char *expand_name(char *dst, int size, char *str, int dev_id)   {       register int sp, np, olen;       char *opt, buf[10];      #ifdef ANDROID_EXPAND_NAME       char value[PROPERTY_VALUE_MAX];   #endif   //這裡當然不是null了       if (!str || !dst)           return NULL;          sp = np = 0;       while (np < size - 1 && str[sp]) {           switch (str[sp]) {           case '%':               opt = NULL;                  switch (str[sp+1]) {               case 'd':   ……   //我們是%m,所以會走到這裡   #ifdef ANDROID_EXPAND_NAME               case 'b':                   property_get("ro.product.brand", value, "");                   opt = value;               break;   //得到ro.product.model的值               case 'm':                   property_get("ro.product.model", value, "");                   opt = value;               break;   ……   #endif                  case '%':                   dst[np++] = str[sp++];                   /* fall through */               default:                   sp++;                   continue;               }                  if (opt) {                   /* substitute */       //保存到adapter.name中                   olen = strlen(opt);                   if (np + olen < size - 1)                       memcpy(dst + np, opt, olen);                   np += olen;               }               sp += 2;               continue;              case '\\':               sp++;               /* fall through */           default:               dst[np++] = str[sp++];               break;           }       }       dst[np] = '\0';       return dst;   }         2-2 sdp_init_services_list   這個函數主要就是把開始的service record和對應的adapter關聯起來   [cpp]  void sdp_init_services_list(bdaddr_t *device)   {       sdp_list_t *p;          DBG("");   //access_db就是開始那邊sdp record會加入的       for (p = access_db; p != NULL; p = p->next) {           sdp_access_t *access = p->data;           sdp_record_t *rec;              if (bacmp(BDADDR_ANY, &access->device))               continue;       //得到對應的sdp record           rec = sdp_record_find(access->handle);           if (rec == NULL)               continue;              SDPDBG("adding record with handle %x", access->handle);       //加入到每一個adapter中,這裡其實也就是一個了       //這裡其實就是會調用adapter_service_insert函數           manager_foreach_adapter(adapter_service_insert, rec);       }   }   void adapter_service_insert(struct btd_adapter *adapter, void *r)   {       sdp_record_t *rec = r;       gboolean new_uuid;       //看adapter services中是否已經有了該uuid       if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp) == NULL)           new_uuid = TRUE;       else           new_uuid = FALSE;       //把這個rec加入到adapter services中       adapter->services = sdp_list_insert_sorted(adapter->services, rec,                                   record_sort);          if (new_uuid) {           //add uuid,新的uuid,則需要調用hciops中的add uuid           uint8_t svc_hint = get_uuid_mask(&rec->svclass);           //調用hciops對應的add_uuid,就是下面的hciops_add_uuid           adapter_ops->add_uuid(adapter->dev_id, &rec->svclass, svc_hint);       }       //因為adapter還沒有初始化完成,所以這個不會做什麼,直接return而已       adapter_emit_uuids_updated(adapter);   }   static int hciops_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)   {       struct dev_info *dev = &devs[index];       struct uuid_info *info;          DBG("hci%d", index);       //新建一個uuid info用來保存這個新的uuid       info = g_new0(struct uuid_info, 1);       memcpy(&info->uuid, uuid, sizeof(*uuid));       info->svc_hint = svc_hint;       //加入到dev->uuids列表中       dev->uuids = g_slist_append(dev->uuids, info);          return update_service_classes(index);   }   static int update_service_classes(int index)   {       struct dev_info *dev = &devs[index];       uint8_t value;       int err;       //uuid對應的service class集合       value = generate_service_class(index);          DBG("hci%d value %u", index, value);          /* Update only the service class, keep the limited bit,       * major/minor class bits intact */       dev->wanted_cod &= 0x00ffff;       dev->wanted_cod |= (value << 16);          /* If the cache is enabled or an existing CoD write is in progress       * just bail out */       //我們這邊的cached_enable是置為true的,所以,暫時就直接return了,後面等到了再分析吧       if (dev->cache_enable || dev->pending_cod)           return 0;   ……   }         2-3 plugin的adapter driver的加載   在2.2.7中,我們詳細分析了各個plugin的初始化,他們最後也注冊了一系列的adapter_driver,這裡我們就是把這些driver進行初始化。   [cpp]   //其實就是遍歷adapter_drivers列表,然後probe driver   static void load_drivers(struct btd_adapter *adapter)   {       GSList *l;          for (l = adapter_drivers; l; l = l->next)           probe_driver(adapter, l->data);   }   static void probe_driver(struct btd_adapter *adapter, gpointer user_data)   {       struct btd_adapter_driver *driver = user_data;       int err;       //檢查是否已經up       if (!adapter->up)           return;       //檢查是否有probe函數       if (driver->probe == NULL)           return;       //調用對應的probe       err = driver->probe(adapter);       if (err < 0) {           error("%s: %s (%d)", driver->name, strerror(-err), -err);           return;       }       //加入到loaded_drivers列表中       adapter->loaded_drivers = g_slist_prepend(adapter->loaded_drivers,                                       driver);   }         從2.3.7的最後,我們發現最終注冊到adapter_driver列表中的有:a2dp_server_driver,avrcp_server_driver,input_server_driver,network_server_driver,hdp_adapter_driver。所以,下面我們就這些進行一下分析。我們以a2dp_server_driver為例進行分析,其它的就比較類似了,不多做解釋。   a2dp_server_driver的probe函數分析   [cpp]   static int a2dp_server_probe(struct btd_adapter *adapter)   {       struct audio_adapter *adp;       //得到adapter的path       const gchar *path = adapter_get_path(adapter);       bdaddr_t src;       int err;          DBG("path %s", path);       //創建一個audio adapter,開始肯定沒有啦       adp = audio_adapter_get(adapter);       if (!adp)           return -EINVAL;   //得到對應的address       adapter_get_address(adapter, &src);       //a2dp的注冊,很大程度上需要根據config做一些不同的操作       err = a2dp_register(connection, &src, config);       if (err < 0)           audio_adapter_unref(adp);          return err;   }      int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)   {       int sbc_srcs = 1, sbc_sinks = 1;       int mpeg12_srcs = 0, mpeg12_sinks = 0;       gboolean source = TRUE, sink = FALSE, socket = TRUE;       gboolean delay_reporting = FALSE;       char *str;       GError *err = NULL;       int i;       struct a2dp_server *server;          if (!config)           goto proceed;   //關於config,配置如下:   /*  Enable=Sink,Control  Disable=Headset,Gateway,Source  Master=false  FastConnectable=false  [A2DP]  SBCSources=1  MPEG12Sources=0  */       str = g_key_file_get_string(config, "General", "Enable", &err);          if (err) {           DBG("audio.conf: %s", err->message);           g_clear_error(&err);       } else {           if (strstr(str, "Sink"))               source = TRUE; //source是true,是反的啊~~           if (strstr(str, "Source"))               sink = TRUE;           g_free(str);       }       str = g_key_file_get_string(config, "General", "Disable", &err);          if (err) {           DBG("audio.conf: %s", err->message);           g_clear_error(&err);       } else {           if (strstr(str, "Sink"))               source = FALSE;           if (strstr(str, "Source"))               sink = FALSE; //這個是false           if (strstr(str, "Socket"))               socket = FALSE; //socket沒有,所以它還是true           g_free(str);       }       /* Don't register any local sep if Socket is disabled */       //socket肯定是會支持的,所以這裡不會走到       if (socket == FALSE) {           sbc_srcs = 0;           sbc_sinks = 0;           mpeg12_srcs = 0;           mpeg12_sinks = 0;           goto proceed;       }       str = g_key_file_get_string(config, "A2DP", "SBCSources", &err);       if (err) {           DBG("audio.conf: %s", err->message);           g_clear_error(&err);       } else {           sbc_srcs = atoi(str); //sbc_srcs=1           g_free(str);       }          str = g_key_file_get_string(config, "A2DP", "MPEG12Sources", &err);       if (err) {           DBG("audio.conf: %s", err->message);           g_clear_error(&err);       } else {           mpeg12_srcs = atoi(str);//MPEG12Source=0           g_free(str);       }          str = g_key_file_get_string(config, "A2DP", "SBCSinks", &err);       if (err) {           DBG("audio.conf: %s", err->message);           g_clear_error(&err);       } else {           sbc_sinks = atoi(str); //默認為1           g_free(str);       }       str = g_key_file_get_string(config, "A2DP", "MPEG12Sinks", &err);       if (err) {           DBG("audio.conf: %s", err->message);           g_clear_error(&err);       } else {           mpeg12_sinks = atoi(str); //默認為0           g_free(str);       }   proceed:       //沒有connection,先得到connection       if (!connection)           connection = dbus_connection_ref(conn);       //找到servers中的a2dp_server       server = find_server(servers, src);       if (!server) {           int av_err;   //沒有,就新建一個           server = g_new0(struct a2dp_server, 1);           if (!server)               return -ENOMEM;   //建一個avdpt的server,並開始一個l2cap的io監聽           av_err = avdtp_init(src, config, &server->version);           if (av_err < 0) {               g_free(server);               return av_err;           }           //拷貝到server src中           bacpy(&server->src, src);           //把新建的server加入到servers中           servers = g_slist_append(servers, server);       }       if (config)           delay_reporting = g_key_file_get_boolean(config, "A2DP",                           "DelayReporting", NULL);       //根據配置,看version,決定是1.3還是1.2       if (delay_reporting)           server->version = 0x0103;       else           server->version = 0x0102;       //source是enable的       server->source_enabled = source;       if (source) {           for (i = 0; i < sbc_srcs; i++)               a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,                   A2DP_CODEC_SBC, delay_reporting, NULL, NULL);           for (i = 0; i < mpeg12_srcs; i++)               a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,                       A2DP_CODEC_MPEG12, delay_reporting,                       NULL, NULL);       }       //sink是沒有enable的       server->sink_enabled = sink;       if (sink) {           for (i = 0; i < sbc_sinks; i++)               a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK,                   A2DP_CODEC_SBC, delay_reporting, NULL, NULL);              for (i = 0; i < mpeg12_sinks; i++)               a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK,                       A2DP_CODEC_MPEG12, delay_reporting,                       NULL, NULL);       }          return 0;   }   int avdtp_init(const bdaddr_t *src, GKeyFile *config, uint16_t *version)   {       GError *err = NULL;       gboolean tmp, master = TRUE;       struct avdtp_server *server;       uint16_t ver = 0x0102;          if (!config)           goto proceed;       //master = false       tmp = g_key_file_get_boolean(config, "General",               "Master", &err);       if (err) {           DBG("audio.conf: %s", err->message);           g_clear_error(&err);       } else           master = tmp;       //auto_connect = true       tmp = g_key_file_get_boolean(config, "General", "AutoConnect",               &err);       if (err)           g_clear_error(&err);       else           auto_connect = tmp;       //這裡是沒有了,所以是0102,就是V1.2,支持delayreporting就是v1.3了       if (g_key_file_get_boolean(config, "A2DP", "DelayReporting", NULL))           ver = 0x0103;      proceed:       //新建avdtp的server       server = g_new0(struct avdtp_server, 1);       if (!server)           return -ENOMEM;          server->version = ver;       //version傳給調用的       if (version)           *version = server->version;       //建一個l2cap的監聽io       server->io = avdtp_server_socket(src, master);       if (!server->io) {           g_free(server);           return -1;       }          bacpy(&server->src, src);       //加入到servers列表中          servers = g_slist_append(servers, server);          return 0;   }      struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,                   uint8_t codec, gboolean delay_reporting,                   struct media_endpoint *endpoint, int *err)   {       struct a2dp_server *server;       struct a2dp_sep *sep;       GSList **l;       uint32_t *record_id;       sdp_record_t *record;       struct avdtp_sep_ind *ind;       //找到a2dp server       server = find_server(servers, src);       if (server == NULL) {           if (err)               *err = -EINVAL;           return NULL;       }          if (type == AVDTP_SEP_TYPE_SINK && !server->sink_enabled) {           if (err)               *err = -EPROTONOSUPPORT;           return NULL;       }       //檢查一下是否對應       if (type == AVDTP_SEP_TYPE_SOURCE && !server->source_enabled) {           if (err)               *err = -EPROTONOSUPPORT;           return NULL;       }       //初始化a2dp sep       sep = g_new0(struct a2dp_sep, 1);       //傳入的是null       if (endpoint) {           ind = &endpoint_ind;           goto proceed;       }       //是sbc       ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;      proceed:       //初始化一個local sep,並把它加入到server sep列表中       sep->lsep = avdtp_register_sep(&server->src, type,                       AVDTP_MEDIA_TYPE_AUDIO, codec,                       delay_reporting, ind, &cfm, sep);       if (sep->lsep == NULL) {           g_free(sep);           if (err)               *err = -EINVAL;           return NULL;       }       //初始化a2dp的sep       sep->server = server;       sep->endpoint = endpoint;       sep->codec = codec;       sep->type = type;       sep->delay_reporting = delay_reporting;          if (type == AVDTP_SEP_TYPE_SOURCE) {           l = &server->sources;           record_id = &server->source_record_id;       } else {           l = &server->sinks;           record_id = &server->sink_record_id;       }       //開始這個是0了       if (*record_id != 0)           goto add;       //service record       record = a2dp_record(type, server->version);       if (!record) {           error("Unable to allocate new service record");           avdtp_unregister_sep(sep->lsep);           g_free(sep);           if (err)               *err = -EINVAL;           return NULL;       }       //把record和server相關聯,這裡也會有UUIDS的property change       if (add_record_to_server(&server->src, record) < 0) {           error("Unable to register A2DP service record");\           sdp_record_free(record);           avdtp_unregister_sep(sep->lsep);           g_free(sep);           if (err)               *err = -EINVAL;           return NULL;       }       //record id用來表示record的handle       *record_id = record->handle;      add:       //加入到server source的列表中       *l = g_slist_append(*l, sep);          if (err)           *err = 0;       return sep;   }         至此,a2dp的probe函數就結束了,主要就是根據配置,新建了a2dp server和a2dp sep,並把對應的service record加入到了server中。   2-4 load_devices的分析   這個函數就是建立了一系列的文件,然後根據文件的內容會有一系列的函數進行對應的處理   [cpp]   static void load_devices(struct btd_adapter *adapter)   {       char filename[PATH_MAX + 1];       char srcaddr[18];       struct adapter_keys keys = { adapter, NULL };       int err;       //把bt的addrees取出保存到srcaddr中       ba2str(&adapter->bdaddr, srcaddr);       //新建profiles文件       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "profiles");       //找到對應key和value,然後調用create_stored_device_from_profiles進行處理,這裡是空的,沒什麼好做       textfile_foreach(filename, create_stored_device_from_profiles,                                   adapter);       //新建primary       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "primary");       textfile_foreach(filename, create_stored_device_from_primary,                                   adapter);       //新建linkkeys       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys");       textfile_foreach(filename, create_stored_device_from_linkkeys, &keys);       //調用load keys,設置dev的key和debug keys元素       err = adapter_ops->load_keys(adapter->dev_id, keys.keys,                               main_opts.debug_keys);       if (err < 0) {           error("Unable to load keys to adapter_ops: %s (%d)",                               strerror(-err), -err);           g_slist_foreach(keys.keys, (GFunc) g_free, NULL);           g_slist_free(keys.keys);       }       //創建blocked       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked");       textfile_foreach(filename, create_stored_device_from_blocked, adapter);       //創建types       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "types");       textfile_foreach(filename, create_stored_device_from_types, adapter);   }         2.4.2.4.2 btd_adapter_get_mode的分析   總的來說還是蠻簡單的,就是根據配置,設置mode,on_mode,和pairable。   [cpp]   void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,                       uint8_t *on_mode, gboolean *pairable)   {       char str[14], address[18];          ba2str(&adapter->bdaddr, address);          if (mode) {           //這裡是false,所以,直接設置為main_opts.mode,就是MODE_CONNECTABLE           if (main_opts.remember_powered == FALSE)               *mode = main_opts.mode;           else if (read_device_mode(address, str, sizeof(str)) == 0)               *mode = get_mode(&adapter->bdaddr, str);           else               *mode = main_opts.mode;       }          if (on_mode) {           //false,read config中的on mode的值,默認為MODE_CONNECTABLE           if (main_opts.remember_powered == FALSE)               *on_mode = get_mode(&adapter->bdaddr, "on");           else if (read_on_mode(address, str, sizeof(str)) == 0)               *on_mode = get_mode(&adapter->bdaddr, str);           else               *on_mode = main_opts.mode;       }       //設置為adapter的pairable       if (pairable)           *pairable = adapter->pairable;   }         2.4.2.4.3 start_adapter的分析   adapter的啟動,這個過程同樣將會涉及到很多的command和event的交互,可以認為是打開藍牙的第二波大規模的command和event交互了,所幸的是,有很多的內容是和之前的是類似的。所以,我們的分析相對而言會比較輕松一點。   [cpp]   static void start_adapter(int index)   {       struct dev_info *dev = &devs[index];       uint8_t inqmode;       uint16_t link_policy;       //發送set event mask的cmd       set_event_mask(index);       //根據是否支持simple pair來決定是否write simple pairing mode的cmd       if (dev->features[6] & LMP_SIMPLE_PAIR)           init_ssp_mode(index);       //看inquiry的mode,然後再決定是否write inquiry mode的cmd       inqmode = get_inquiry_mode(index);       if (inqmode)           write_inq_mode(index, inqmode);       //是否支持inquiry tx power,然後決定是否發送read inquiry response tx power level的cmd       if (dev->features[7] & LMP_INQ_TX_PWR)           hci_send_cmd(dev->sk, OGF_HOST_CTL,                   OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL, 0, NULL);          /* Set default link policy */       link_policy = main_opts.link_policy;          if (!(dev->features[0] & LMP_RSWITCH))           link_policy &= ~HCI_LP_RSWITCH;       if (!(dev->features[0] & LMP_HOLD))           link_policy &= ~HCI_LP_HOLD;       if (!(dev->features[0] & LMP_SNIFF))           link_policy &= ~HCI_LP_SNIFF;       if (!(dev->features[1] & LMP_PARK))           link_policy &= ~HCI_LP_PARK;       //發送write default link policy來設置link的策略       link_policy = htobs(link_policy);       hci_send_cmd(dev->sk, OGF_LINK_POLICY, OCF_WRITE_DEFAULT_LINK_POLICY,                       sizeof(link_policy), &link_policy);          dev->current_cod = 0;       memset(dev->eir, 0, sizeof(dev->eir));   }         從log來看,在開始的時候只會發送set event mask和write default link policy的cmd。這兩個cmd在kernel層的處理我們已經分析過了,都沒有做什麼,再回到bluez層,我們會發現其實也沒有對這兩個cmd的處理,所以,我們就不管了。繼續往下分析好了。       2.4.2.4.4 btd_adapter_start的分析   初始化adaptere的一些內容,不可避免地仍然會涉及到各種command和event的交互。主要就是兩個command,write local name和write device of class。   [cpp]   void btd_adapter_start(struct btd_adapter *adapter)   {       char address[18];       uint8_t cls[3];       gboolean powered;          ba2str(&adapter->bdaddr, address);          adapter->dev_class = 0;       adapter->off_requested = FALSE;       adapter->up = TRUE;       adapter->discov_timeout = get_discoverable_timeout(address);       adapter->pairable_timeout = get_pairable_timeout(address);       adapter->state = STATE_IDLE;       adapter->mode = MODE_CONNECTABLE;          if (main_opts.le)           adapter_ops->enable_le(adapter->dev_id);       //通過write local name來設置controller的name       adapter_ops->set_name(adapter->dev_id, adapter->name);       //得到config文件中的class的值       if (read_local_class(&adapter->bdaddr, cls) < 0) {           //若是沒有得到,就拷貝main opts中的class           uint32_t class = htobl(main_opts.class);           memcpy(cls, &class, 3);       }       //調用write class of device command來設置device class       //但是因為cached_enable是true,所以,他並不會調用這個cmd       //而是在後面的disable_cod_cache中調用       btd_adapter_set_class(adapter, cls[1], cls[0]);          powered = TRUE;       //向上層通知powered的改變,為true了,也是property change,這個會在後面的分析中詳細介紹       emit_property_changed(connection, adapter->path,                       ADAPTER_INTERFACE, "Powered",                       DBUS_TYPE_BOOLEAN, &powered);       //就headset中用到過,這裡沒有,所以直接返回了       call_adapter_powered_callbacks(adapter, TRUE);       //調用write class of device command來設置device class       adapter_ops->disable_cod_cache(adapter->dev_id);          info("Adapter %s has been enabled", adapter->path);   }         這個函數涉及到的兩個cmd:write local name和write device of class,其中write local name的command complete是沒有什麼需要做的。而write device of class在bluez中是有很多操作的,我們需要詳細分析一下:   1)write device of class的command complete分析:   [cpp]  static void write_class_complete(int index, uint8_t status)   {       struct dev_info *dev = &devs[index];       struct btd_adapter *adapter;          //status非0的話說明有問題,好像開始沒有介紹,這裡介紹一次後面不再說了       if (status)           return;          if (dev->pending_cod == 0)           return;       //設置當前的coditon       dev->current_cod = dev->pending_cod;       //把pending去除掉       dev->pending_cod = 0;          adapter = manager_find_adapter(&dev->bdaddr);       //保存class到config文件中,並通知上層property change       if (adapter)           btd_adapter_class_changed(adapter, dev->current_cod);       //根據ex inquiry的feature決定是否需要update       update_ext_inquiry_response(index);       //這裡就直接return了       if (dev->wanted_cod == dev->current_cod)           return;       //若不是,則需要再次進行一次class的write       if (dev->wanted_cod & LIMITED_BIT &&               !(dev->current_cod & LIMITED_BIT))           hciops_set_limited_discoverable(index, TRUE);       else if (!(dev->wanted_cod & LIMITED_BIT) &&                       (dev->current_cod & LIMITED_BIT))           hciops_set_limited_discoverable(index, FALSE);       else           write_class(index, dev->wanted_cod);   }         總的來說,他就是把class的值保存到對應的config文件中,然後向上層通知了class的property的change。       2.4.2.4.5 write scan enable,inquiry cancel的分析   從write scan enable的command complete處理來看,他會直接發送read scan enable的cmd。   [cpp]  case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):           hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_SCAN_ENABLE,                                   0, NULL);           break;   inquiry cancel的command complete:   static inline void cc_inquiry_cancel(int index, uint8_t status)   {       //status有問題,只會打印一下       if (status) {           error("Inquiry Cancel Failed with status 0x%02x", status);           return;       }       //設置狀態位DISCOV_HALTED,不過初始化就是這個,所以在打開藍牙的時候這個命令出問題,其實是沒有關系的。事實上很多controller就是不支持這個cmd,還好問題也不大。       set_state   (index, DISCOV_HALTED);   }   下面我們順手再分析一下read scan enable這個cmd的event處理:   static void read_scan_complete(int index, uint8_t status, void *ptr)   {       struct btd_adapter *adapter;       read_scan_enable_rp *rp = ptr;          DBG("hci%d status %u", index, status);          adapter = manager_find_adapter_by_id(index);       if (!adapter) {           error("Unable to find matching adapter");           return;       }       //通知mode 的change       adapter_mode_changed(adapter, rp->enable);   }   void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)   {       const gchar *path = adapter_get_path(adapter);       gboolean discoverable, pairable;          DBG("old 0x%02x new 0x%02x", adapter->scan_mode, scan_mode);       //沒有變化就什麼都不做       if (adapter->scan_mode == scan_mode){   #ifdef BOARD_HAVE_BLUETOOTH_BCM           /*we may reset scan_mode already in btd_adapter_stop(), so comes to here*/           set_mode_complete(adapter);   #endif           return;       }       //這個就是把discov timeout去除掉,開始也沒有,所以,這裡也就沒有什麼       adapter_remove_discov_timeout(adapter);          switch (scan_mode) {       case SCAN_DISABLED:           adapter->mode = MODE_OFF;           discoverable = FALSE;           pairable = FALSE;           break;           //我們是0x02       case SCAN_PAGE:           adapter->mode = MODE_CONNECTABLE;           discoverable = FALSE;           pairable = adapter->pairable;           break;       case (SCAN_PAGE | SCAN_INQUIRY):           adapter->mode = MODE_DISCOVERABLE;           discoverable = TRUE;           pairable = adapter->pairable;           if (adapter->discov_timeout != 0)               adapter_set_discov_timeout(adapter,                           adapter->discov_timeout);           break;       case SCAN_INQUIRY:           /* Address the scenario where a low-level application like           * hciconfig changed the scan mode */           if (adapter->discov_timeout != 0)               adapter_set_discov_timeout(adapter,                           adapter->discov_timeout);              /* ignore, this event should not be sent */       default:           /* ignore, reserved */           return;       }          /* If page scanning gets toggled emit the Pairable property */       //scan page的改變,需要通知上層pairable的property change       if ((adapter->scan_mode & SCAN_PAGE) != (scan_mode & SCAN_PAGE))           emit_property_changed(connection, adapter->path,                       ADAPTER_INTERFACE, "Pairable",                       DBUS_TYPE_BOOLEAN, &pairable);       //這裡discoverable是false       if (!discoverable)           adapter_set_limited_discoverable(adapter, FALSE);       //再通知上層discoverable的property change       emit_property_changed(connection, path,                   ADAPTER_INTERFACE, "Discoverable",                   DBUS_TYPE_BOOLEAN, &discoverable);       //設置adapter的scan mode       adapter->scan_mode = scan_mode;       //設置mode完成       set_mode_complete(adapter);   }         所以,這裡最重要的就是向上面發送了兩個property change,分別為:Pairable=false和Discoverable=false  
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved