成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

鴻蒙開源第三方組件—ANR異常監測組件 ANR-WatchDog-ohos

系統
ANR-WatchDog-ohos是一個監測組件,可以監測鴻蒙應用的ANR(Application Not Response-應用程序無響應)錯誤,并能及時拋出異常。

[[416599]]

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

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

https://harmonyos.51cto.com

前言

基于安卓平臺的消息彈框組件ANR-WatchDog(https://github.com/SalomonBrys/ANR-WatchDog),實現鴻蒙化遷移和重構。代碼已經開源到(https://gitee.com/isrc_ohos/anr-watch-dog-ohos),歡迎各位下載使用并提出寶貴意見!

背景

ANR-WatchDog-ohos是一個監測組件,可以監測鴻蒙應用的ANR(Application Not Response-應用程序無響應)錯誤,并能及時拋出異常。在此組件被移植成功之前,鴻蒙應用程序是無法捕獲和報告ANR錯誤的,調查ANR的唯一方法是查看/data/anr/traces.txt文件。因此ANR-WatchDog-ohos為ANR捕獲過程提供了更好的交互性、便捷性以及可視化的效果,同時也提升了程序的健壯性。

組件效果展示

1、組件應用的界面介紹

為了更好的向開發者展示組件的運行效果,先來了解一下組件應用中各按鈕的含義。在圖1中,藍色框內是ANR的監測模式設置按鈕,紅色框內的是ANR模擬按鈕。下面具體解釋各按鈕的含義:

  • Min ANR duration:阻塞響應時間按鈕。開發者通過點擊按鈕設置阻塞響應時間為2秒、4秒或6秒,即應用阻塞2秒、4秒或6秒后,執行特定的響應行為。
  • Report mode:報告模式按鈕。開發者通過點擊按鈕設置ANR發生時,HiLog中輸出錯誤報告的模式:All Threads表示輸出每個線程的錯誤日志;Main thread only 表示只輸出主線程的錯誤日志;Filtered表示只輸出符合特定過濾條件的線程的錯誤日志。
  • Behaviour:響應行為按鈕。開發者通過點擊按鈕設置ANR發生時應用的響應行為:Crash表示應用閃退;Silent表示開發者自定義應用的響應行為。
  • Thread Sleep:可以模擬主線程休眠。
  • Infinite loop:可以模擬主線程無限循環。
  • Dead lock:可以模擬主線程死鎖。
鴻蒙開源第三方組件——ANR異常監測組件 ANR-WatchDog-ohos-鴻蒙HarmonyOS技術社區

圖1 ANR-WatchDog-ohos組件應用的界面介紹

2、組件運行效果展示

通過點擊圖1紅色框內三個不同的按鈕,可以看到三種不同的ANR發生時組件的運行效果。為了更清楚的展現檢測模式的作用,我們給每個ANR模擬按鈕設置不同的檢測模式。下面對組件的運行效果進行詳細描述:

1、線程休眠

ANR監測模式:阻塞響應時間為2秒,報告模式為All Threads、響應行為Crash。

點擊Thread Sleep按鈕,啟動主線程休眠后,ANR-WatchDog-ohos組件監測到程序在2秒內一直無響應,于是觸發應用閃退,并通過HiLog報告所有線程的ANR詳情,其模式設置和執行效果如圖2所示。

在報告中,可以根據“Caused by”后面的堆棧信息追蹤查看線程休眠的具體原因,如圖3所示。

鴻蒙開源第三方組件——ANR異常監測組件 ANR-WatchDog-ohos-鴻蒙HarmonyOS技術社區

圖2 線程休眠設置流程和執行效果

鴻蒙開源第三方組件——ANR異常監測組件 ANR-WatchDog-ohos-鴻蒙HarmonyOS技術社區

圖3 監測線程休眠后閃退輸出的HiLog信息

2、線程無限循環

ANR監測模式:阻塞響應時間為4秒,報告模式為All Threads、響應行為Crash。

點擊Infinite loop按鈕,啟動線程無限循環后,ANR-WatchDog-ohos組件監測到程序在4秒內一直無響應,于是觸發應用閃退,并通過HiLog報告主線程的ANR錯誤詳情,其監測模式設置和執行效果如圖4所示,HiLog報告主線程的ANR詳情如圖5所示。

鴻蒙開源第三方組件——ANR異常監測組件 ANR-WatchDog-ohos-鴻蒙HarmonyOS技術社區

圖4 線程無限循環設置流程和執行效果

鴻蒙開源第三方組件——ANR異常監測組件 ANR-WatchDog-ohos-鴻蒙HarmonyOS技術社區

圖5 監測線程無限循環后閃退輸出的HiLog信息

3、線程死鎖

ANR監測模式:阻塞響應時間為6秒,報告模式為Filtered(只報告以“APP:”為前綴的線程)、響應行為Crash。

點擊Dead lock按鈕,啟動線程死鎖后,ANR-WatchDog-ohos組件監測到程序在6秒內一直無響應,于是觸發應用閃退,并通過HiLog報告以“APP:”為前綴線程的ANR錯誤詳情,其監測模式設置和執行效果如圖6所示,HiLog報告主線程的ANR詳情如圖7所示。

鴻蒙開源第三方組件——ANR異常監測組件 ANR-WatchDog-ohos-鴻蒙HarmonyOS技術社區

圖6 線程死鎖設置流程和執行效果

鴻蒙開源第三方組件——ANR異常監測組件 ANR-WatchDog-ohos-鴻蒙HarmonyOS技術社區

圖7 監測線程死鎖后閃退輸出的HiLog信息

值得注意的是:無論在哪種ANR類型下,只要將Behaviour設置為Silent,應用遇到ANR時的響應行為都需要開發者自定義。例如此處我們定義:應用遇到ANR的情況時,通過HiLog打印出ANR-Watchdog-Demo的tag,如圖7所示:

鴻蒙開源第三方組件——ANR異常監測組件 ANR-WatchDog-ohos-鴻蒙HarmonyOS技術社區

圖8 Silent行為下不閃退只輸出HiLog信息

Sample解析

ANR-WatchDog-ohos組件能夠監測多種類型的ANR錯誤,及時捕捉并觸發相應的響應行為。下面將具體講解ANR-WatchDog-ohos組件的使用方法,共分為7個步驟,其中步驟1至步驟2在MyApplication文件中進行,步驟3至步驟7在MainAbility文件中進行:

步驟1. 導入相關類并實例化類對象。

步驟2. 設置ANRListener監聽。

步驟3. 模擬主線程休眠、無限循環和死鎖。

步驟4. 創建xml文件。

步驟5. 設置整體布局,并實例化MyApplication對象。

步驟6. 設置ANR檢測模式Button的點擊事件。

步驟7. 設置ANR模擬Button的點擊事件。

(1)導入相關類并實例化類對象

在MyApplication文件中,導入ANRError類和ANRWatchDog類并實例化ANRWatchDog類的對象,設置默認的阻塞響應時間Min ANR duration為2000毫秒(2秒)。其中,ANRWatchDog類的作用是檢測ANR的情況是否出現,ANRError類的作用是拋出錯誤信息,即正在運行線程的堆棧追蹤信息。

  1. //導入ANRError類和ANRWatchDog類 
  2. import com.github.anrwatchdog.ANRError; 
  3. import com.github.anrwatchdog.ANRWatchDog; 
  4. //實例化ANRWatchDog類對象 
  5. ANRWatchDog anrWatchDog = new ANRWatchDog(2000);//設置阻塞響應時間為2000毫秒(2秒) 

(2)設置ANRListener監聽

當響應行為按鈕設置為Crash:

由于MyApplication類繼承了AbilityPackage類,因此需要重寫onInitialize()方法。在onInitialize()方法中,需要調用ANRWatchDog類的setANRListener()方法,為應用設置ANR監聽,其中onAppNotResponding()方法用于在上述監聽中設置應用的ANR響應行為,此處設置ANR情況發生時,應用crash并拋出異常。當需要提前或推遲報告ANR錯誤或者執行響應行為時,在onInitialize()方法中,可以通過調用ANRWatchDog類的setANRInterceptor()方法設置攔截器,實現在給定的響應時間內對異常或其他自定義的響應行為進行攔截。

  1. //重寫onInitialize()方法 
  2. @Override 
  3. public void onInitialize() { 
  4.     super.onInitialize(); 
  5.     //設置ANRListener監聽 
  6.     anrWatchDog.setANRListener(new ANRWatchDog.ANRListener() {  
  7.                    @Override//設置監測到ANR錯誤后的具體響應行為 
  8.                    public void onAppNotResponding(ANRError error) { 
  9.                        ... 
  10.                     throw error;//直接拋出錯誤異常,程序閃退  } 
  11.             }) 
  12.             .setANRInterceptor(new ANRWatchDog.ANRInterceptor() { 
  13.                 @Override//定義攔截器來決定是否提前或推遲 
  14.                 public long intercept(long duration) {...} 
  15.             }); 
  16.     anrWatchDog.setIgnoreDebugger(true).start();//在debug的情況下也能拋出ANR異常 

當響應行為按鈕設置為Silent:

此時需要設置ANRListener 類的對象為final 對象,對象內部的內容可變,但是引用不會變。我們定義:線程阻塞后程序不閃退,而是打印ANR-Watchdog-Demo的tag,因此在重寫ANRWatchDog類的onAppNotResponding()方法時,只需要自定義相應的Hilog報告即可,不需要拋出異常。

  1. final ANRWatchDog.ANRListener silentListener = new ANRWatchDog.ANRListener() { 
  2.     @Override//重寫setANRListner()方法 
  3.     public void onAppNotResponding(ANRError error) {//自定義ANRListener回調 
  4.         HiLog.error(new HiLogLabel(HiLog.LOG_APP,0,"ANR-Watchdog-Demo"), "", error); 
  5.     } 
  6. }; 

(3)模擬線程休眠、線程無限循環和線程死鎖

為了使ANR-WatchDog-ohos能監測到如線程休眠、線程無限循環和線程死鎖不同情況下的ANR,需要分別設置函數,模擬這三種情況。

線程休眠

  1. private static void Sleep() {//模擬線程休眠的情況 
  2.     try { 
  3.         Thread.sleep(8 * 1000);//線程休眠8秒后釋放鎖 
  4.     } 
  5.     catch (InterruptedException e) { 
  6.         e.printStackTrace(); 
  7.     } 

線程無限循環

  1. private static void InfiniteLoop() {//模擬線程無限循環的情況 
  2.     int i = 0; 
  3.     while (true) {//判斷條件恒為true,則無限循環 
  4.         i++; 
  5.     } 

線程死鎖

  1. private  void  lock(){//模擬線程死鎖的情況 
  2.     new Thread(){ 
  3.         @Override 
  4.         public void run(){ 
  5.             synchronized (MainAbility.this){//線程占用鎖 
  6.                 try{ 
  7.                     Thread.sleep(60000);//休眠60秒后釋放鎖 
  8.                 } 
  9.             ...} 
  10.     }.start(); 
  11.     synchronized (MainAbility.this){//主線程也同時占用鎖 
  12.         HiLog.info(new HiLogLabel(HiLog.LOG_APP,0,"ANR-Failed"),"主線程也申請鎖"); 

(4)創建xml文件

在ability_main.xml中創建顯示文件,最主要的部分是圖1藍框中3個模式設置按鈕和紅框中3個ANR類型的按鈕。

  1. <DirectionalLayout//創建整體布局 
  2.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  3.     ohos:height="match_parent" 
  4.     ohos:width="match_parent" 
  5.     ohos:orientation="vertical"
  6.     ... 
  7.     //圖1紅框中的按鈕 
  8.     <Button         //阻塞響應時間按鈕 
  9.         ohos:id="$+id:minAnrDuration" 
  10.         ohos:width="match_content" 
  11.         ohos:height="match_content" 
  12.         ohos:text="2s" 
  13.    ohos:text_size="150"/> 
  14.         ...      //報告模式按鈕和響應行為按鈕同上 
  15. //圖1紅框中的按鈕 
  16.     <Button     //線程休眠按鈕 
  17.     ohos:id="$+id:threadSleep" 
  18.         ohos:left_margin="24" 
  19.         ohos:width="match_content" 
  20.         ohos:height="match_content" 
  21.     ohos:text="$string:threadsleep" 
  22.     .../> 
  23.          ...    //線程無限循環按鈕和死鎖按鈕同上 
  24. </DirectionalLayout> 

(5)設置整體布局,并實例化MyApplication對象

通過setUIContent()方法加載上一步設置好的xml文件作為整體顯示布局,實例化MyApplication對象為后續設置各按鈕的點擊事件做準備。

  1. setUIContent(ResourceTable.Layout_ability_main);//加載UI布局 
  2. final MyApplication application = (MyApplication) getAbilityPackage();//實例化 

(6)設置ANR檢測模式Button的點擊事件

本步驟需要阻塞響應時間、報告模式和響應行按鈕的點擊事件。

阻塞響應時間Button

為實現每點擊按鈕一次就切換一種阻塞響應時間,需要用公式將變量application.duration控制在2秒、4秒和6秒之間。application.duration的初始值為4,每點擊一次按鈕,將application.duration整除6的余數加上2的值重新復制給application.duration,可以實現上述切換效果。

  1. minAnrDurationButton.setClickedListener(new Component.ClickedListener() { 
  2.     @Override//重寫onClick()方法 
  3.     public void onClick(Component component) { 
  4.         application.duration = application.duration % 6 + 2;//得到整除6的余數加2 
  5.         minAnrDurationButton.setText(application.duration + " seconds"); 
  6.     } 
  7. }); 

報告模式Button

為實現每點擊按鈕一次就切換一種報告模式,需要用公式將變量mode控制在0、1、2這三個值中。0表示All Threads;1表示Main thread only;2表示Filtered。mode初始值為0,所以第一次點擊后mode值變為1,通過setReportMainThreadOnly()方法設置為只報告主線程,其他情況與上述類似。

  1. reportModeButton.setClickedListener(new Component.ClickedListener() { 
  2.     @Override//重寫onClick()方法 
  3.     public void onClick(Component component) { 
  4.         mode = (mode + 1) % 3;//得到mode加1并整除3后的余數 
  5.         switch (mode) { 
  6.             case 0: 
  7.                 ...//所有線程 
  8.                 application.anrWatchDog.setReportAllThreads();break ; 
  9.             case 1: 
  10.                 ...//只有主線程 
  11.                 application.anrWatchDog.setReportMainThreadOnly();break ; 
  12.             case 2: 
  13.                 ...//過濾以“APP:”為前綴的線程 
  14.               application.anrWatchDog.setReportThreadNamePrefix("APP:");break ; 
  15.         } 
  16.     } 
  17. }); 

響應行為Button

crash變量是ANR響應行為的標志位,為實現每點擊按鈕一次就切換一種響應行為,需要判斷crash變量是否為true。如果crash變量為true,則說明在監測到ANR錯誤后應用直接閃退,需要通過setANRListener()方法調用步驟(2)中響應行為為Crash時的onAppNotResponding()方法;反之,則說明開發者自定義了監測到ANR錯誤后應用的響應行為,需要通過setANRListener()方法調用步驟(2)中的響應行為為Silent時的onAppNotResponding()方法。

  1. behaviourButton.setClickedListener(new Component.ClickedListener() { 
  2.     @Override//重寫onClick()方法 
  3.     public void onClick(Component component) { 
  4.         crash = !crash;每次點擊更改crash的布爾類型 
  5.         if (crash) {//crash為true 
  6.             behaviourButton.setText("Crash"); 
  7.             application.anrWatchDog.setANRListener(null);//無需設置回調 
  8.         } else {//crash不為true 
  9.             behaviourButton.setText("Silent");//自定義ANRListener回調 
  10.            application.anrWatchDog.setANRListener(application.silentListener); 
  11.         } 
  12.     } 

(7)設置ANR模擬Button的點擊事件

最后需要設置線程休眠、線程無限循環和線程死鎖按鈕的點擊事件。此處以線程休眠按鈕為例,只需在對應的onClick()方法中調用各自的模擬函數即可,其他兩種情況同理。

  1. findComponentById(ResourceTable.Id_threadSleep).setClickedListener(new Component.ClickedListener() {//線程休眠Button的click點擊事件 
  2.     @Override 
  3.     public void onClick(Component component) {//重寫onClick()方法 
  4.         Sleep();//調用模擬線程休眠的函數 
  5.     } 
  6. }); 

Library解析

Library包含兩個重要的類,即ANRWatchDog和ANRError,它們向開發者提供使用ANR-WatchDog-ohos組件監測并處理ANR錯誤的具體執行方法,本節將分別講解ANRWatchDog類和ANRError類的內部邏輯。

1、ANRWatchDog類

(1)構造方法阻塞響應時間

ANRWatchDog類繼承自Thread類,其實質是一個線程,因此根據線程的特性,我們可以隨時將其中斷。ANRWatchDog類提供了兩個構造方法,使用第二個帶參的構造方法,開發者能夠對阻塞響應時間進行設置,使用第一個不帶參的構造方法,阻塞響應時間默認配置為5000ms。

  1. //構造方法一 
  2. public ANRWatchDog() { 
  3.     this(DEFAULT_ANR_TIMEOUT);//使用默認的阻塞響應時間5000ms 
  4. //構造方法二 
  5. public ANRWatchDog(int timeoutInterval) { 
  6.     super(); 
  7.     _timeoutInterval = timeoutInterval;//自定義阻塞響應時間timeoutInterval 

(2)任務單元_ticker判斷主線程是否阻塞

鴻蒙開源第三方組件——ANR異常監測組件 ANR-WatchDog-ohos-鴻蒙HarmonyOS技術社區

圖9 監測主線程是否阻塞的原理

在ANRWatchDog類中,監測主線程是否阻塞的具體原理流程如圖9,其核心是向主線程拋出一個Runnable類型的任務單元_ticker,然后判斷其在特定時間內是否被主線程處理,若_ticker被處理,說明主線程未阻塞,需要進行循環判斷。若未被處理,說明主線程阻塞,需要向開發者發送ANR錯誤信息。

變量_tick標志著_ticker是否被處理,其初始值為0,并且是volatile類型的,這個類型的好處是能夠保證此變量在被不同線程操作時的可見性,即如果某線程修改了此變量的值,那么新值對其他線程來說是立即可見的。在未執行在_ticker之前,_tick的值為阻塞響應時間,執行了_ticker后,_tick的值會被重置為0,因此只需要判斷_tick值是否被重置為0即可獲知_ticker是否被處理。

  1. private volatile long _tick = 0; //用于標志_ticker是否被處理 
  2. private volatile boolean _reported = false
  3. private final Runnable _ticker = new Runnable() { 
  4.     @Override public void run() {//_ticker處理線程 
  5.         _tick = 0;//重置為初始值0,表示_ticker被處理 
  6.         _reported = false
  7.     } 
  8. }; 

復制 在ANRWatchDog類的run()方法中,先通過_tick值判斷_ticker是否被發送給主線程,如果_tick的值為0則有兩種情況,一種是_tick的初始值為0,_ticker從未被發送給主線程;另一種是_ticker完成了一次或多次發送周期,且均被主線程處理,_tick被重置為0。在上述兩種情況下,需要將_tick值加上一段阻塞響應時間后重新發送給主線程。

  1. @Override 
  2. public void run() {//ANRWatchDog類的執行過程 
  3.     setName("|ANR-WatchDog|"); 
  4.     long interval = _timeoutInterval; 
  5.     while (!isInterrupted()) { 
  6.         boolean needPost = _tick == 0;//將“_tick是初始值0”賦給needPost 
  7.         _tick += interval;//_tick值加一個阻塞響應時間 
  8.         if (needPost) {//判斷_tick是否為0 
  9.             _uiHandler.postTask(_ticker);//發送_ticker給主線程 
  10.         } 
  11. ...}  

如果_tick的值不為0,此時ANRWatchDog線程需要休眠一個阻塞響應時間(對應圖的1藍框中的Min ANR duration)。休眠結束后,繼續根據_tick的值可以判斷_ticker是否被處理,如果_tick被重置為0,則說明主線程處理了_ticker,主線程未阻塞;反之則說明主線程沒有處理_ticker,主線程阻塞,需要通過ANRError類拋出錯誤信息(具體操作間ANRError類的介紹),并返回一個ANRError類的實例。

  1. try { 
  2.     Thread.sleep(interval);//ANRWatchDog線程休眠一個阻塞響應時間 
  3. } catch (InterruptedException e) { 
  4.     _interruptionListener.onInterrupted(e); 
  5.     return ; 
  6. if (_tick != 0 && !_reported) {//如果主線程沒有處理_ticker,則主線程阻塞 
  7.     ... 
  8.     final ANRError error;//聲明ANRError類 
  9.     if (_namePrefix != null) {//調用ANRError類的New()方法 
  10.             error = ANRError.New(_tick, _namePrefix, _logThreadsWithoutStackTrace); 
  11.     } else {//調用ANRError類NewMainOnly()方法 
  12.             error = ANRError.NewMainOnly(_tick); 
  13.     } 

隨后,調用ANRListener類onAppNotResponding()方法設置主線程阻塞后的響應行為(對應圖1藍框中的Behaviour)。

  1. _anrListener.onAppNotResponding(error);  //響應行為設置 

2、 ANRError類

ANRError類繼承自Error類,主要用于拋出錯誤信息,其有兩個重要的方法,分別是New()方法和NewMainOnly()方法。以下兩段代碼分別展示了兩個方法的具體邏輯。通過對比可發現這兩個方法的處理過程其實是類似的,核心都是先通過getMainEventRunner()方法獲取主線程mainThread ;再通過主線程得到堆棧信息mainStackTrace ,最后以mainThread和mainStackTrace作為參數實例化ANRError對象,并將該對象作為函數返回值。

NewMainOnly()方法

  1. static ANRError NewMainOnly(long duration) { 
  2.     final Thread mainThread =  //通過getMainEventRunner()方法獲取到主線程findThread(EventRunner.getMainEventRunner().getThreadId()); 
  3.     //獲取堆棧信息 
  4.     final StackTraceElement[] mainStackTrace = mainThread.getStackTrace(); 
  5.     return new ANRError(new $(getThreadTitle(mainThread), mainStackTrace).new _Thread(null), duration);//返回重新構造的ANRError實例 

New()方法

  1. static ANRError New(long duration, String prefix, boolean logThreadsWithoutStackTrace) { 
  2.     final Thread mainThread = //通過getMainEventRunner()方法獲取到主線程findThread(EventRunner.getMainEventRunner().getThreadId()); 
  3.     final Map<Thread, StackTraceElement[]> stackTraces = new TreeMap<Thread, StackTraceElement[]>(new Comparator<Thread>() {@Override...});//獲取堆棧信息 
  4.     ... 
  5.     for (Map.Entry<Thread, StackTraceElement[]> entry : stackTraces.entrySet()) 
  6.         tst = new $(getThreadTitle(entry.getKey()), entry.getValue()).new _Thread(tst);//重新構造ANRError實例 
  7.     return new ANRError(tst, duration);//返回重新構造的ANRError實例 

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

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

https://harmonyos.51cto.com

 

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

2021-04-20 15:06:42

鴻蒙HarmonyOS應用

2021-07-06 18:21:31

鴻蒙HarmonyOS應用

2021-04-08 14:57:52

鴻蒙HarmonyOS應用

2021-08-30 17:55:58

鴻蒙HarmonyOS應用

2021-07-20 15:20:40

鴻蒙HarmonyOS應用

2021-04-15 17:47:38

鴻蒙HarmonyOS應用

2021-11-02 14:54:21

鴻蒙HarmonyOS應用

2021-06-29 09:28:16

鴻蒙HarmonyOS應用

2021-03-24 09:30:49

鴻蒙HarmonyOS應用

2021-11-17 15:37:43

鴻蒙HarmonyOS應用

2021-07-28 09:40:04

鴻蒙HarmonyOS應用

2021-03-03 09:42:26

鴻蒙HarmonyOS圖片裁剪

2021-10-19 10:04:51

鴻蒙HarmonyOS應用

2021-04-29 14:32:24

鴻蒙HarmonyOS應用

2021-03-10 15:03:40

鴻蒙HarmonyOS應用

2021-08-26 16:07:46

鴻蒙HarmonyOS應用

2021-03-01 14:00:11

鴻蒙HarmonyOS應用

2021-06-17 14:56:00

鴻蒙HarmonyOS應用

2021-08-05 15:06:30

鴻蒙HarmonyOS應用

2021-08-03 10:07:41

鴻蒙HarmonyOS應用
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: www.久| 久久亚洲欧美日韩精品专区 | 欧美国产日韩在线观看成人 | 国内精品视频在线观看 | 免费九九视频 | 精品乱码一区二区三四区 | 国产高清一区二区 | 免费日韩网站 | 大久| 亚洲精品乱码 | 日韩综合一区 | 亚洲一区日韩 | 国产免费视频在线 | 亚洲激情自拍偷拍 | 精品国产视频在线观看 | 午夜爽爽爽男女免费观看 | 在线视频 欧美日韩 | 欧美 日韩 国产 成人 在线 | 日韩视频一区二区三区 | 天天搞天天操 | 男人天堂网av | 中文字幕乱码一区二区三区 | 国产亚洲人成a在线v网站 | 亚洲人在线 | 日韩欧美国产精品 | 国产精品高潮呻吟久久 | 噜噜噜噜狠狠狠7777视频 | 国产91av视频 | 久久美国 | 亚洲精品乱码久久久久久蜜桃91 | 国产乱码精品一区二区三区中文 | 综合激情av | av男人的天堂在线 | 亚洲在线免费 | av大全在线观看 | 亚洲精品综合一区二区 | 美女三区 | 亚洲国产免费 | 国内精品视频免费观看 | 中文字幕高清一区 | 亚洲欧美日韩在线 |