精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Hi3861的SAMGR--系統服務框架子系統-2

系統
文章由鴻蒙社區產出,想要了解更多內容請前往:51CTO和華為官方戰略合作共建的鴻蒙技術社區https://harmonyos.51cto.com

[[404768]]

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

 接前文《Hi3861的SAMGR--系統服務框架子系統-1

4 結構體的分解

4.1 先上samgr的展開圖【附件有原圖】

4.2 Samgr:SamgrLiteImpl g_samgrImpl

  1.      typedef struct SamgrLiteImpl SamgrLiteImpl; 
  2.         struct SamgrLiteImpl  { 
  3. A:          SamgrLite vtbl;       //SAMGR_GetInstance() return this SamgrLite Instance 
  4. B:          MutexId mutex; 
  5. C:          BootStatus status;    //see BootStatus 
  6. D:          Vector services;      //a vector to record all services 
  7. E:          TaskPool *sharedPool[MAX_POOL_NUM]; 
  8.         }; 

 注冊第一個服務的時候,首先要通過SAMGR_GetInstance()從全局變量g_samgrImpl獲取一個samgr的實例對象,g_samgrImpl已經初始化過了的話,可以直接返回samgr對象的引用,g_samgrImpl沒有初始化的話,就需要通過Init函數進行初始化相關的配置之后,才能返回samgr對象的引用。

以后的各種service/feature的操作,基本是都是需要通過g_samgrImpl進行管理的。下面把這個全局變量展開來看一下:

A: SamgrLite vtbl;

vtbl 就是SamgrLite 的實例,SAMGR_GetInstance() 時,返回的就是指向它的指針。SamgrLite結構體(或者直接說類)定義了四組十個函數指針,如下圖,同一組用同一個顏色框起來:

在g_samgrImpl的初始化(init)時與對應的實現函數對應關聯起來,之后就可以通過這四組函數來對service/ feature進行注冊、注銷、獲取API等操作了。

而具體的service、feature在各自INIT時,會通過g_samgrImpl的samgr實例調用這里的Register接口,向g_samgrImpl注冊自己和API,把自己納入samgr的管理體系中,然后就是samgr為service、feature創建queue/taskpool/task等運行環境了。

B: MutexId mutex;

互斥鎖。關鍵代碼段的操作要加鎖,保證多線程下對共享數據的操作的完整性。

在g_samgrImpl的初始化(init)時就會通過MUTEX_InitValue() 生成互斥鎖,MUTEX_InitValue()聲明在thread_adapter.h,它的實現則取決于平臺使用的內核,M核平臺用cmsis接口來實現,A核/Linux平臺,則使用posix接口來實現。

類似的還有內存、隊列、線程、timer的相關操作,代碼見:

  1. Hi3861/foundation/distributedschedule/samgr_lite/samgr/adapter/ 

理論上,全局對象g_samgrImpl初始化(init)時就會生成一個mutex,且只要g_samgrImpl沒有重新初始化,這個mutex就應該是不變的,Hi3861平臺上我看到的也確實如此。

但是Hi3516平臺上我看到了一個奇怪的地方,見前文《鴻蒙系統框架層的啟動細節》的附件log,搜索關鍵字“SAMGR_GetInstance|StartServiceByName|Invoke: msg”可以看到:

有若干處mutex是為NULL的,需要重新初始化g_samgrImpl,這樣豈不是會把之前注冊的service Vector/TaskPool等清除掉嗎?先存疑,待進一步仔細閱讀Hi3516的代碼后再確認。

C: BootStatus status;

系統的啟動階段狀態標記。

Hi3861平臺上電啟動到 system_init.c 的

  1. void HOS_SystemInit(void) 
  2.     ...... 
  3.     SYS_INIT(service); 
  4.     SYS_INIT(feature); 
  5.     SAMGR_Bootstrap(); 

 這一步時,通過SYS_INIT() 啟動的都是用SYS_SERVICE_INIT()和SYS_FEATURE_INIT() 標記的service和feature,而通過SYSEX_SERVICE_INIT/APP_SERVICE_INIT/ SYSEX_FEATURE_INIT/APP_FEATURE_INIT 標記的service和feature,則會在系統啟動到 BOOT_APP 這一步時,由Bootstrap service來啟動,見 bootstrap_service.c 的MessageHandle()函數內的 INIT_APP_CALL() 的調用:

系統啟動狀態標記到 BOOT_DYNAMIC 這一步時,意味著系統所有的應用服務也啟動完畢了,進入了一個比較穩定的狀態,至于BOOT_DYNAMIC狀態還會做其他什么事情,我暫時還沒有更多的了解。

為了理解例程代碼如何工作,我在這里加了 BOOT_DEBUG和BOOT_DEBUG_WAIT兩個狀態,用來調用例程里的INIT_TEST_CALL(),跑相關的測試流程,通過相關的log來驗證自己的分析,詳見附件的log。

D: Vector services;

g_samgrImpl 初始化時:

  1. g_samgrImpl.services = VECTOR_Make((VECTOR_Key)GetServiceName, (VECTOR_Compare)strcmp); 

創建了一個Vector:{0, 0, 0, NULL, key, compare},Vector的定義如下:

其中:

  • max:表示下面的**data指針數組的大小,也就是data[max]所能存儲的最大指針數目;
  • top: 當前使用到了的指針數組的最高位置data[top],當top==max,同時free為0時,表示data[max]已經裝滿了,需要擴容,一次擴容增加4個element位置,變成data[max+4],詳情見VECTOR_Add()函數的實現。
  • free:當前0~top之間,釋放了的位置的數量。當已注冊在冊的service unregister時,對應記錄這個service的data[i]會被清空,free+1;下次有新的service注冊時,會優先使用data[i]來記錄新service的Impl對象指針,free-1。詳情見VECTOR_Swap()函數的實現
  • **data:指針數組data[max],每一個data[i]記錄了一個注冊進來的service對應的ServiceImpl 對象的指針,初始化為NULL,通過VECTOR_Add()函數內的操作擴容。
  • key:是samgr_lite.c定義的GetServiceName(ServiceImpl*)函數指針,它可以通過參數來獲取對應的service Name。
  • compare:是strcmp函數指針,也就是string標準庫提供的字符串比較函數。

Samgr通過這個Vector來管理所有注冊進來的service(實際上管理的是serviceImpl對象,通過serviceImpl來關聯具體的service和service對應的feature)。

每個service可以有0個/1個或多個feature,每個service(serviceImpl對象)也是通過自己的Vector來管理feature。

對Vector的操作,全部定義在:

Hi3861/foundation/distributedschedule/services/samgr_lite/samgr/source/common.c

里面了,需要仔細閱讀分析,去理解相關操作。

下面是幾處要點:

  • VECTOR_Make() 會創建一個{0, 0, 0, NULL, key, compare} Vector,當需要往Vector中添加element時,會在VECTOR_Add()中擴容。
  • VECTOR_Add(Vector *vector, void *element) 的時候,發現Vector的data[max] 空間用盡了,就會重新申請一塊增大了4個element的內存空間Newdata[max+4],把舊的data[x]全部拷貝進去(還有4個新的空余的element位置),g_samgrImpl.services.data重新指向Newdata,再把舊的data[x]占用的空間釋放掉,這樣,新的element (ServiceImpl 對象的指針)就可以記錄進來了。
  • VECTOR_Swap()用來刪除一個已經記錄在案的element(也就是unregister一個service),把它對應的 data[x] 置為NULL,free+1,空出的位置會給未來新注冊的service 優先使用。
  • VECTOR_Find()/VECTOR_FindByKey() 可以查找element(serviceImpl),并返回它的index。

特別是VECTOR_FindByKey(Vector *vector, const void *key),第二個參數“void *key”實際上是一個service的名字字符串,如“Broadcast”。

FindByKey會循環獲取data[0~top]的ServiceImpl 對象的指針,并將其作為key函數指針(GetServiceName())的參數來獲取service的Name,將Name其與上面的第二個參數的service Name,用compare函數指針(strcmp)進行對比,匹配則返回對應的data[i]的 index i。

E: TaskPool *sharedPool[MAX_POOL_NUM]; // MAX_POOL_NUM 是8

Hi3861平臺啟動到 system_init.c 的最后一步時:

  1. void HOS_SystemInit(void) 
  2.     ...... 
  3.     SAMGR_Bootstrap();   

 調用SAMGR_Bootstrap()去啟動已經注冊了的service,會為service創建queue和taskPool資源,每個service有一個GetTaskConfig()接口,可以返回這個service運行起來的task配置參數,如 bootstrap service的TaskConfig為:

請自行查看 TaskConfig的定義。

這里需要關注的是 SHARED_TASK 這個標記,在samgr的 AddTaskPool()這一步時:

bootstrap service的TaskConfig配置會被修改成默認的DEFAULT_TASK_CFG,意味著在bootstrap_service.c 中定義的TaskConfig 參數(stackSize和queueSize)其實并沒有起作用,想要修改SHARED_TASK的stackSize和queueSize,要去修改DEFAULT_TASK_CFG的配置。

而上面case SHARED_TASK的操作以及g_samgrImpl.sharedPool[]的存在,可以為若干個共同標記了SHARED_TASK的service共享一個Queue和taskPool資源(這樣可以節約好多資源),TaskEntry在Queue中收到msg時,可以通過Exchange 消息里面的Identity字段解析出Sid/Fid/Qid信息,以此來確認到底是哪個service/feature需要處理這個消息。

TaskConfig里的priority字段,則確定了service用的是哪個sharePool[x],優先級越高,x越大。

我在代碼里全局搜索了一下“SHARED_TASK”關鍵字,得到如下結果:

主要是在samgr例程里,不同優先級別的service,共享著不同x的sharedPool[x]資源。

不是SHARED_TASK的service則有自己獨立的Queue和taskPool,不會直接記錄在g_samgrImpl.sharedPool[]里,而是記錄在各自service的serviceImpl對象的taskPool* 里。

4.3 ServiceImpl 類

  1.     struct ServiceImpl { 
  2. A:      Service*      service; 
  3. B:      IUnknown* defaultApi; 
  4. C:      TaskPool*   taskPool; 
  5. D:      Vector    features; 
  6. E:      int16      serviceId; 
  7. F:      uint8      inited; 
  8. G:      Operations ops; 
  9.     }; 

 g_samgrImpl 全局變量的services Vector里,只直接記錄ServiceImpl對象的指針,并不直接記錄和管理service、feature對象本身。service在向samgr注冊自己時,samgr會首先生成一個ServiceImpl對象,將service對象的指針記錄在ServiceImpl的Service* service里,而ServiceImpl對象本身的指針,則記錄在g_samgrImpl.services.data[i] 中,這樣就建立了g_samgrImpl 到具體service的聯系,見本文上面的展開圖。

A: Service* service;    

指向當前ServiceImpl對象所對應的具體的service對象,這些具體的service對象都是Service類的子類對象。

B: IUnknown* defaultApi;

繼承了IUnknown接口(INHERIT_IUNKNOWN)的service或者feature,都會有IUnknown的一組三個默認的接口,這組接口主要是記錄service/feature對象的引用數量,還可以通過其中的QueryInterface接口實現父類(IUnknown)指針到具體的service/feature子類對象指針的類型轉換,以獲取子類提供的功能。

詳情見下面對IUnknown的分析。

我在《鴻蒙的DFX子系統 》一文中,有對hiview service做過一個展開,可以去那里了解一下。

C: TaskPool* taskPool;

這就是上一小節中,samgr為service創建的taskPool的指針(同時創建的還有消息隊列,queueId同時保存在taskPool里面)。

如果service task是SHARED_TASK類型的,那就會有多個service共享一個taskPool和queue,這里的taskPool指針就會指向同一塊內存空間,同時,g_samgrImpl的對應優先級別的sharedPool[x]也會記錄著這個taskPool指針。

如果service task不是SHARED_TASK類型的,那就只會在這里記錄service的taskPool(包括queue),而不會在g_samgrImpl中做記錄。

D: Vector features;

feature需要依賴于對應的service才能注冊和運行,一個service可以有0個、1個或多個feature。service本身不記錄它對應的feature的信息,而是由這個ServiceImpl.features來記錄。ServiceImpl 的這個Vector features類似于g_samgrImpl用于記錄serviceImpl的Vector services。

一個service沒有feature時,features Vector就保持初始化的樣子,對應的features.data 是NULL。

一個service有若干個feature時,就會在feature注冊時,由samgr生成對應FeatureImpl類對象,將此對象與具體的feature關聯起來,再將此對象的指針保存在Vector features.data[x]里,并將這個 x 作為對應feature的ID,另做保存。以后samgr就可以通過它自己的vector找到serviceImpl,再進一步通過這個vector找到對應的featureImpl,從而找到最終的feature。

E: int16 serviceId;

當前的ServiceImpl 對象指針保存在g_samgrImpl.services vector內的data[x]上的這個 x 序號,就作為當前service的ID,保存在這里。這個serviceId也可能同時保存在具體的service對象的Identity 結構體里。

F: uint8 inited;

標記當前ServiceImpl 對應的service的狀態,service沒有init起來是不能注冊feature的,service在處理消息事件的時候,狀態也要對應置為 BUSY,處理完消息又要將狀態寫回IDLE。具體可自行查閱代碼。

G: Operations ops;

主要記錄了service處理消息事件的時間戳、msg數量(編號?)、步驟和是否存在異常等信息,估計與跨設備的服務/消息處理的同步有關,對此暫未做深入理解,待作進一步的理解。

4.4 FeatureImpl類

  1.   typedef struct FeatureImpl FeatureImpl; 
  2.     struct FeatureImpl { 
  3. A:      Feature  *feature; 
  4. B:      IUnknown *iUnknown; 
  5.     }; 

 FeatureImpl 類看起來相對簡單,直接是一個Feature指針(A)指向對應的具體的feature對象。

有些feature除了繼承自Feature類之外,還繼承了某些interface,為feature提供額外的功能,這些interface 都是繼承了最原始的IUnknown接口類(INHERIT_IUNKNOWN)。

這里的IUnknown *iUnknown與上面的ServiceImpl 的IUnknown* defaultApi; 其實是同一個東西,它們都指 向了一個feature或者service所繼承/實現的接口中,IUnknown接口所在的位置,見上面ServiceImpl對IUnknown* defaultApi;的說明。

更多詳情見下面對IUnknown的分析。

4.5 Service類及其子類

  1. struct Service { 
  2.     const char *(*GetName)(Service *service);                   //獲取service名稱 
  3.     BOOL (*Initialize)(Service *service, Identity identity);    //service的初始化 
  4.     BOOL (*MessageHandle)(Service *service, Request *request);  //service的消息處理函數 
  5.     TaskConfig (*GetTaskConfig)(Service *service);              //獲取service 任務運行的配置 

 Service類是所有service類的父類,它聲明了四個函數指針,這是每一個服務都必須要實現的生命周期函數,見上面的注釋。

每一個具體的服務類都繼承自這個Service類,然后可以擴展自己獨特的功能。

下面分別看一下Hi3861默認的三個具體的服務。

A: Bootstrap service

  1. typedef struct Bootstrap { 
  2.     INHERIT_SERVICE;  //繼承上面的Sevice類 
  3.     Identity identity;   //bootstrap service對象的id信息 
  4.     uint8 flag; 
  5. } Bootstrap; 

 Bootstrap 除了繼承Service之外,還增加了一個Identity identity 和 uint8 flag。

  • Identity identity

這是Bootstrap service具體對象的身份信息,里面包括了: serviceId/featureId/queueId三個信息。

serviceId:Bootstrap service 對應的 serviceImpl對象,在g_samgrImpl.services這個Vector.data[]中存放位置 的index,這里值為0.

featureId:Bootstrap service不帶feature,所以值為 -1。

queueId: Bootstrap service啟動時,samgr會為其創建消息隊列,這就是消息隊列的ID,是一串數字。

  • uint8 flag

一個標記,主要是LOAD_FLAG 0x01這一個位,用來標記非系統service/feature是否已經加載和注冊,見 bootstrap_service.c的MessageHandle()內對flag的使用。

B. Broadcast service

  1. typedef struct BroadcastService BroadcastService; 
  2. struct BroadcastService { 
  3.     INHERIT_SERVICE; 
  4. }; 

 Broadcast service僅僅直接繼承了Service類,確保它的service對象的生命周期的完整,因為它還會有feature,會在具體的feature對象中保存id信息和其它擴展信息,詳見下面的PubSubFeature類的解析。

C. Hiview service

  1. typedef struct { 
  2.     INHERIT_IUNKNOWN;     
  3.     void (*Output)(IUnknown *iUnknown, int16 msgId, uint16 type); 
  4. } HiviewInterface; 
  5.  
  6. typedef struct { 
  7.     INHERIT_SERVICE; 
  8.     INHERIT_IUNKNOWNENTRY(HiviewInterface); 
  9.     Identity identity; 
  10. } HiviewService;  

 Hiview service除了繼承自Service類實現service的生命周期函數之外,還繼承了HiviewInterface,這個HiviewInterface又繼承了最原始的IUnknown接口類(INHERIT_IUNKNOWN)。通過這種多繼承機制,既實現了服務所需的生命周期,又具備了類似feature所提供的部分接口功能(Hiview service實際上又不帶feature)。

詳情見下面對IUnknown類的分析。

identity則是Hiview service對象的身份信息,同樣包括了: serviceId/featureId/queueId三個信息。

4.6 Feature類及其子類

  1. struct Feature { 
  2.     const char *(*GetName)(Feature *feature);                         //獲取feature的名字 
  3.     void (*OnInitialize)(Feature *feature, Service *parent, Identity identity);  //feature 的初始化 
  4.     void (*OnStop)(Feature *feature, Identity identity);                   //停止對外提供feature功能 
  5.     BOOL (*OnMessage)(Feature *feature, Request *request);             //對本feature的消息處理 
  6. }; 

 Feature類是所有feature類的父類,也是聲明了四個函數指針,這是每一個feature都必須要實現的生命周期函數,見上面的注釋。

每一個具體的feature類都繼承自這個Feature類,然后擴展自己獨特的功能。

下面是Hi3861的Broadcast service 提供的feature類及Impl類的定義:

A: PubSubFeature g_broadcastFeature

  1. typedef struct PubSubFeature PubSubFeature; 
  2. struct PubSubFeature { 
  3.     INHERIT_FEATURE;   //繼承 Feature 類 
  4.     Relation *(*GetRelation)(PubSubFeature *feature, const Topic *topic); 
  5.     MutexId mutex; 
  6.     Relation relations; 
  7.     Identity identity; 
  8. }; 

 PubSubFeature 本尊,它被FeatureImpl 對象以及下面的PubSubImplement 對象引用。

FeatureImpl 對象又會被記錄在 ServiceImpl 的Features Vector向量里,獲得一個Fid,連同Sid/Qid一起記錄在PubSubFeature 的identity里。

PubSubFeature 還提供一個雙向鏈表結構的Relation,以及基于這個雙向鏈表結構的查找節點的函數GetRelation(),這個結構及其作用,我后面再另寫文章詳細分析。

B: PubSubImplement g_pubSubImplement

  1. typedef struct PubSubInterface PubSubInterface; 
  2. struct PubSubInterface { 
  3.     INHERIT_IUNKNOWN; 
  4.     Subscriber subscriber; 
  5.     Provider provider; 
  6. }; 
  7.  
  8. typedef struct PubSubImplement { 
  9.     INHERIT_IUNKNOWNENTRY(PubSubInterface); 
  10.     PubSubFeature *feature; 
  11. } PubSubImplement; 

 PubSubImplement 對象會引用上面的PubSubFeature對象,記錄在這里的PubSubFeature *feature上。

PubSubImplement 還繼承了PubSubInterface,實現了Subscriber 和Provider的功能。

它們的關系,見本文最上面的展開圖。

這個PubSubFeature 和PubSubImplement 深究下去就有點復雜了,它們是SOA(面向服務的架構)的具體實現:

  • Provider:服務的提供者,為系統提供能力(對外接口)。
  • Consumer:服務的消費者,調用服務提供的功能(對外接口)。
  • Samgr:作為中介者,管理Provider提供的能力,同時幫助Consumer發現Provider的能力。

如下是官方readme上畫的架構圖。

這里我就先不做進一步詳細的分析了,后面會結合broadcast_example.c示例程序來做分析和驗證,再單獨寫一篇文章來做總結。

4.7 IUnknown 接口類及其相關定義

首先需要理解,C語言的struct本質上與C++中的class是一樣的,都是一塊存儲區域,里面有數據和對數據的操作。C++通過“:”關鍵字來標記繼承關系,如Aa繼承自A表示為“class Aa : public A”,而C語言直接是struct Aa內嵌套struct A來標記“繼承關系”:

  1. struct A { 
  2.     dataA; 
  3.     funcPtr* funcA; 
  4. struct Aa { 
  5.     struct A; 
  6.     dataAa; 
  7.     funcPtr* funcAa; 

 更具體的一些細節,可以自行在網上搜索和學習。

接下來,我們仔細對比一下HivieService 和PubSubImplement,它們都分別通過INHERIT_IUNKNOWNENTRY() 這個關鍵字來分別繼承HiviewInterface和PubSubInterface,而這HiviewInterface和PubSubInterface又都通過INHERIT_IUNKNOWN來繼承IUnknown接口類。

下面我們就跟著Hi3861/foundation/distributedschedule/interfaces/innerkits/samgr_lite/samgr/iunknown.h中的定義去展開和理解一下這兩個宏(類)。

INHERIT_IUNKNOWN 宏定義是為了方便用C語言的形式“繼承”IUnknown接口類。

INHERIT_IUNKNOWNENTRY() 宏定義是為了方便用C語言的形式“繼承”【實現了IUnknown接口的】 IUnknownEntry接口類。

這兩個宏之間的關系,就是上面struct A和struct Aa之間的父類子類關系,換回struct 的形式,就是:

IUnknown 是父類,IUnknownEntry 是子類,子類是父類的一個implement。

按上面的定義把HiviewService類(或結構體)的定義徹底展開,就是如下的樣子:

把HiviewService的全局對象 g_hiviewService的初始化也按上面的形式展開,也會如下:

這樣一來,.iUnknown的地址、HiviewService類型、g_hiviewService對象的地址(引用/指針)之間的關系,就可以通過計算和類型轉換來互相獲取了,這就是下面三個宏的作用:

a. GET_IUNKNOWN(T)

定義在://foundation/distributedschedule/interfaces/innerkits/samgr_lite/samgr/iunknown.h

簡單理解為:從g_hiviewService對象中獲取其內部的.iUnknown對象的地址。

b. GET_OFFSIZE(T, member)

c. GET_OBJECT(Ptr, T, member)

這兩個定義在://foundation/distributedschedule/interfaces/innerkits/samgr_lite/samgr/common.h

簡單理解為:從.iUnknown父類對象下轉換得到子類HiviewInterface對象或者g_hiviewService對象的地址。

如本文開頭的第一張展開圖所示,BroadcastImpl和HiviewImpl都有自己的 IUnknown* defaultApi,分別是通過GET_IUNKNOWN(g_pubSubImplement) 和GET_IUNKNOWN(g_hiviewService)來得到的,得到了.iUnknown的地址,也就是得到了(*QueryInterface)/(*AddRef)/(*Release)這三個defaultApi的地址,就可以使用它們了,實際只直接使用(*QueryInterface)這個API,它的作用是“Queries the subclass object of the IUnknown interface of a specified version”

查詢/獲取指定的版本的IUnknown接口的子類對象(同時增加對該對象的引用次數),調用者通過這個子類對象就可以調用子類中定義的其它接口了。

對于上面的g_hiviewService例子來說,調用QueryInterface接口的例子在hiview_service.c 的HiviewSendMessage() 里,它返回的實際上就是g_hiviewService 這個service對象內部的一個區域的起始地址,這個區域就是HiviewInterface這個類的對象,同時增加了對這個對象的引用次數,之后,就可以通過這個對象來調用HiviewInterface所定義的全部API了(這里主要是Output函數)。

4.8 其它類/結構體

samgr子系統中還有其他的一些很重要的類或結構體,比如Request/Response/Exchange 等等,這里就先不進一步展開了,以后應該還會繼續補充完整的,或者在接下來的流程分析中按需進行分解,也請各位自行做一下理解。

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

 

責任編輯:jianghua 來源: 鴻蒙社區
相關推薦

2021-06-03 14:21:44

鴻蒙HarmonyOS應用

2021-06-18 10:02:10

鴻蒙HarmonyOS應用

2021-06-18 15:23:59

鴻蒙HarmonyOS應用

2021-07-08 16:16:59

鴻蒙HarmonyOS應用

2021-07-05 09:35:36

鴻蒙HarmonyOS應用

2021-07-07 09:45:20

鴻蒙HarmonyOS應用

2021-07-12 09:50:39

鴻蒙HarmonyOS應用

2022-03-15 15:00:59

Hi3861Pin接口鴻蒙

2020-10-16 09:50:37

Hi3861WiFi熱點

2021-04-30 09:43:27

鴻蒙HarmonyOS應用

2023-05-26 16:07:14

Hi3861Wifi模塊

2022-03-07 15:05:58

HTTPHi3861數據解析

2020-11-03 11:39:22

wifi小車

2020-10-30 09:41:44

鴻蒙Hi3861WiFi小車

2020-10-14 09:41:02

Hi3861GPIO點燈

2021-07-01 14:21:58

鴻蒙HarmonyOS應用

2022-05-30 15:21:27

Hi3861TCP通信

2020-11-02 12:07:11

鴻蒙 GPIO

2020-10-28 10:03:43

Hi3861 GPIO點燈按鍵

2020-10-12 09:36:04

鴻蒙
點贊
收藏

51CTO技術棧公眾號

久久精品国产亚洲7777| 亚洲不卡一区二区三区| 91精品国产综合久久香蕉| 99久久精品久久亚洲精品| 国产95亚洲| 午夜精品福利在线| 日产精品高清视频免费| 精品国自产拍在线观看| 国产精品久久久久久久免费软件 | 国模gogo一区二区大胆私拍| 久久久精品人妻无码专区| 婷婷精品久久久久久久久久不卡| 亚洲国产欧美日韩另类综合| 日韩视频精品| 黄频网站在线观看| 丁香婷婷久久| 洋洋av久久久久久久一区| 蜜桃视频日韩| 国产情侣在线播放| 久久亚洲二区| 欧美精品久久久久久久久| 你懂得视频在线观看| 黄色在线网站噜噜噜| 国产欧美一区二区三区在线看蜜臀 | 美女视频黄a大片欧美| 欧美精品videos另类日本| 一二三四国产精品| 秋霞在线一区| 精品国产免费视频| 超碰成人在线播放| 日韩不卡免费高清视频| 午夜日韩在线电影| 国产亚洲精品久久久久久久| 国产黄在线播放| 99精品热视频| 国产一区在线观| 国产女人18毛片18精品| 毛片av中文字幕一区二区| 51ⅴ精品国产91久久久久久| 精品在线视频免费观看| 围产精品久久久久久久| 一区二区三区四区视频| 泷泽萝拉在线播放| 荡女精品导航| 3atv一区二区三区| av在线网址导航| 久久xxx视频| 色狠狠桃花综合| 亚洲色欲综合一区二区三区| 51av在线| 精品毛片三在线观看| avav在线播放| 欧美视频一二区| 国产最新精品精品你懂的| 国产精品久久久久久久美男 | aaa在线观看| 久久久蜜桃精品| 欧美日韩精品免费看| 亚洲欧美自偷自拍| 久久久亚洲精品一区二区三区| 精品卡一卡二| 日本中文字幕一区二区有码在线 | 三级资源在线| 亚洲一区二区三区四区五区中文| 成人在线免费观看视频网站| aa在线视频| 一区二区三区在线视频观看| 成年人视频网站免费| 亚洲小说区图片| 亚洲一区二区三区不卡国产欧美 | 亚洲欧美日本日韩| 欧美一区二区三区四区在线| 亚洲天堂男人av| 日韩精彩视频在线观看| 国产精品一区二区三区在线播放| 亚洲最新av网站| 国产精品资源网| 成人在线视频网址| 水莓100在线视频| 国产色爱av资源综合区| 久久精品欧美视频| 久久综合精品国产一区二区三区 | 国产成人精品久久| 一区二区视频在线免费观看| 久久福利影视| 国产精品日韩电影| 中文字幕免费高清在线观看| 中文字幕精品视频在线| 中文字幕免费看| 美女主播精品视频一二三四| 亚洲欧洲日本专区| 久久精品日产第一区二区三区乱码| chinese国产精品| 蜜臀久久99精品久久久久宅男| 成人激情av在线| 少妇av在线播放| 国产视频一区二区在线观看| 美国av在线播放| 爱搞国产精品| 欧美日韩一区视频| 欧美夫妇交换xxx| 精品国产乱码久久久| 欧美肥婆姓交大片| 日韩精品一区二区亚洲av观看| 精彩视频一区二区三区| 精品一区二区不卡| 米奇精品一区二区三区| 韩国av一区二区三区在线观看| yy111111少妇影院日韩夜片 | 国产成人一级电影| 欧美久久综合性欧美| а√天堂8资源在线官网| 欧美日韩在线另类| 尤物网站在线看| 亚洲品质自拍| 欧美丰满少妇xxxx| 亚洲一卡二卡在线| 久久先锋影音av| 精品人妻大屁股白浆无码| 福利精品一区| 亚洲毛片在线看| 久视频在线观看| 国内欧美视频一区二区| 欧美一进一出视频| 国产在线观看www| 日韩欧美一级二级| 国产精品久久久免费看| 久久久久久久波多野高潮日日| 成人黄色片视频网站| 快射视频在线观看| 米奇精品关键词| 欧美大片一区二区三区| 黑人と日本人の交わりビデオ| av成人国产| 国产激情美女久久久久久吹潮| 岛国大片在线观看| 日韩欧美在线播放| 日本黄色片在线播放| 国内自拍视频一区二区三区| 亚洲在线一区二区| 免费人成在线观看播放视频| 在线免费观看一区| 成人黄色免费网址| 久色成人在线| 视频一区二区三| 国产精品久久久久av电视剧| 亚洲精品在线视频| 国产无套丰满白嫩对白| 久久综合狠狠综合久久激情| 精品欧美一区免费观看α√| 西西44rtwww国产精品| 四虎国产精品成人免费入口| 视频一区国产| 久久精品这里热有精品| 亚洲中文字幕一区二区| 天天射天天色天天干| 国产精品啊啊啊| 91入口在线观看| 1区2区在线观看| 91精选在线观看| 国产狼人综合免费视频| 日韩精品在线观看网站| 激情五月婷婷六月| 国产一区二区| 久久精品成人欧美大片| 亚洲图片小说视频| 国产精品久久久久久久第一福利| 国产又猛又黄的视频| 第一社区sis001原创亚洲| 日韩精彩视频在线观看| 99久久99久久精品国产片桃花 | 性高湖久久久久久久久aaaaa| 精品国产一区二区三区2021| 九九热r在线视频精品| www.日韩高清| 欧美日韩在线免费观看| 色播亚洲视频在线观看| 91亚洲永久免费精品| 亚洲一区二区在线免费| 欧美特黄一级| 国产乱码精品一区二区三区卡 | 国产精品久久看| 亚洲黄色av片| 亚洲第一网站| 在线日韩一区二区| 中文天堂在线一区| 亚洲人成电影网站色| 成人在线观看高清| 高清视频一区二区| 日韩网址在线观看| 成人久久久久| 999国内精品视频在线| 僵尸再翻生在线观看免费国语| 久久久久久免费视频| 日韩精品欧美激情一区二区| 一区二区在线视频| 亚洲综合免费视频| 亚洲高清免费观看| 公肉吊粗大爽色翁浪妇视频| 九九久久精品视频| www.av毛片| 成人看的视频| 日韩视频国产视频| 无码精品一区二区三区在线播放| 久久国产高清| 18视频在线观看娇喘| 国产成人精品福利| 国产成人精品日本亚洲| 国产最新在线| 国产一区二区三区中文| 亚洲精品国产精品国| 欧美专区亚洲专区| 国产精品1000| 国产精品久久久久影院色老大| 久久久久无码国产精品一区李宗瑞| 久久激情一区| www.99热这里只有精品| 91九色精品| 日韩精品伦理第一区| 成人台湾亚洲精品一区二区| 国产综合在线观看视频| 欧美xx视频| 国内精品伊人久久| 污片在线免费观看| 最近中文字幕日韩精品| 噜噜噜在线观看播放视频| 日韩欧美中文一区| 国产乱码精品一区二区三区精东| 色婷婷亚洲一区二区三区| 国产一级视频在线观看| 亚洲日本青草视频在线怡红院| 国产精品久久免费观看| 99热这里都是精品| 日韩精品国产一区| 国产乱人伦偷精品视频不卡| 手机视频在线观看| 亚洲免费中文| 69堂免费视频| 国产日本精品| 欧美亚洲一二三区| 国产精品女主播一区二区三区| 久久手机在线视频| 欧美成人日本| 国产乱子伦精品视频| 亚洲老妇激情| 久久av秘一区二区三区| 色综合天天爱| 一级二级三级欧美| 久久亚洲精品中文字幕蜜潮电影| 日韩性感在线| 欧美亚洲精品在线| 亚洲精品久久区二区三区蜜桃臀| 国产日产精品_国产精品毛片| 久久亚洲综合网| 亚洲精品动态| 免费在线观看91| 美女少妇全过程你懂的久久| 欧美日韩亚洲在线| 狠狠做六月爱婷婷综合aⅴ| 日韩av一级大片| 日韩欧美精品| 国产日产欧美一区二区| 国产精品草草| 久久成人免费观看| 久久中文在线| 日本肉体xxxx裸体xxx免费| 久久精品国产99久久6| 中文字幕 91| 国产激情偷乱视频一区二区三区| 中国特级黄色片| 91色九色蝌蚪| 变态另类ts人妖一区二区| 国产精品久久影院| 免费在线观看黄色av| 偷偷要91色婷婷| 久久久久久不卡| 欧美人与z0zoxxxx视频| www.蜜臀av| 亚洲嫩模很污视频| 五月婷婷在线视频| 欧美裸身视频免费观看| 国产污视频在线播放| 国产精品v日韩精品| 亚洲成a人片777777久久| 97视频资源在线观看| 天堂一区二区三区四区| 亚洲一卡二卡三卡| 国产精品草草| 中文久久久久久| 国产99一区视频免费| 无码h肉动漫在线观看| 成人免费视频在线观看| 国产网址在线观看| 91国产福利在线| 亚洲第一大网站| 亚洲男人的天堂在线| www免费视频观看在线| 51ⅴ精品国产91久久久久久| 亚洲一区导航| 欧美日本韩国国产| 欧美日本精品| 国产精品无码专区av在线播放 | 亚洲综合日韩欧美| 岛国av在线一区| 99国产精品免费| 婷婷国产v国产偷v亚洲高清| 一二三四区视频| 亚洲精品在线不卡| 超碰97国产精品人人cao| 国产精品流白浆视频| 激情小说一区| 二级片在线观看| 免费看精品久久片| 精品国产人妻一区二区三区| 亚洲欧美另类在线| 在线观看国产成人| 亚洲另类图片色| 超级碰碰不卡在线视频| 成人免费网视频| 精品香蕉视频| 国模吧无码一区二区三区| 国产成人a级片| 国产精品视频一区二区在线观看 | 888奇米影视| 亚洲色图50p| 丝袜诱惑一区二区| 国产视色精品亚洲一区二区| 亚洲影视一区二区三区| 伊人国产在线视频| 国产三级久久久| 久久久成人免费视频| 亚洲国产成人一区| 亚洲制服国产| 亚洲一区二区免费在线| 外国成人免费视频| 欧美三级午夜理伦三级富婆| 久久久久高清精品| 成人毛片在线播放| 亚洲老板91色精品久久| 麻豆免费在线| 久久99导航| 久久不射网站| 一级性生活大片| 色狠狠综合天天综合综合| 精品无人乱码| 日韩av男人的天堂| 国产一区二区亚洲| 午夜免费一区二区| 久久久亚洲精品一区二区三区| 视频一区二区三区四区五区| 日韩电影在线观看中文字幕| 三妻四妾完整版在线观看电视剧| 国内精品视频免费| 国产一区二区三区久久| 国产亚洲无码精品| 色婷婷精品久久二区二区蜜臂av | 中国精品一区二区| 少妇高潮 亚洲精品| 懂色av色香蕉一区二区蜜桃| 中文字幕第一页亚洲| 精彩视频一区二区三区| 日韩a级片在线观看| 亚洲成人动漫在线播放| 黄色激情在线播放| 秋霞毛片久久久久久久久| 日韩国产精品久久久| 青青青视频在线播放| 欧美久久一二区| 羞羞的视频在线观看| 精品国产一区二区三区免费 | 久久这里只精品| 亚洲狠狠丁香婷婷综合久久久| 亚洲第一大网站| 日韩免费在线播放| 香港欧美日韩三级黄色一级电影网站| 欧美又黄又嫩大片a级| 亚洲自拍偷拍av| 国产又爽又黄网站亚洲视频123| 热99在线视频| 色琪琪久久se色| 美女黄色一级视频| 91高清视频在线| 4438x成人网全国最大| 国精产品99永久一区一区| 日韩高清在线不卡| 久久国产精品国语对白| 亚洲大胆人体在线| 素人啪啪色综合| 高清无码视频直接看| 国产视频不卡一区| 丰满人妻一区二区| 国产成人久久精品| 欧美三级乱码| 中文字幕丰满乱子伦无码专区| 制服丝袜激情欧洲亚洲| 狠狠操一区二区三区| 浴室偷拍美女洗澡456在线| 91影院在线免费观看| 国产乱码精品一区二区| 国产91在线播放|