日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android深入四大组件(八)广播的注册、发送和接收过程

發(fā)布時(shí)間:2025/3/20 Android 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android深入四大组件(八)广播的注册、发送和接收过程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

我們接著來學(xué)習(xí)Android四大組件中的BroadcastReceiver,廣播主要就是分為注冊、接收和發(fā)送過程。建議閱讀此文前請先閱讀Android深入理解四大組件系列的文章,知識重復(fù)的部分,本文不再贅述。

1.廣播的注冊過程

BroadcastReceiver的注冊分為兩種,分別是靜態(tài)注冊和動態(tài)注冊,靜態(tài)注冊在應(yīng)用安裝時(shí)由PackageManagerService來完成注冊過程,關(guān)于這一過程,我會在后續(xù)的介紹PackageManagerService文章中詳細(xì)介紹。這里只介紹BroadcastReceiver的動態(tài)注冊。
要想動態(tài)注冊BroadcastReceiver,需要調(diào)用registerReceiver方法,它的實(shí)現(xiàn)在ContextWrapper中,代碼如下所示。

frameworks/base/core/java/android/content/ContextWrapper.java

@Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {return mBase.registerReceiver(receiver, filter); } View Code

這里mBase具體指向就是ContextImpl,不明白的請查看Android深入四大組件(二)Service的啟動過程這篇文章。ContextImpl的registerReceiver方法有很多重載的方法最終會調(diào)用registerReceiverInternal方法:
frameworks/base/core/java/android/app/ContextImpl.java

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,IntentFilter filter, String broadcastPermission,Handler scheduler, Context context) {IIntentReceiver rd = null;if (receiver != null) {if (mPackageInfo != null && context != null) {//1if (scheduler == null) {scheduler = mMainThread.getHandler();}rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler,mMainThread.getInstrumentation(), true);//2} else {if (scheduler == null) {scheduler = mMainThread.getHandler();}rd = new LoadedApk.ReceiverDispatcher(receiver, context, scheduler, null, true).getIIntentReceiver();//3 }}try {final Intent intent = ActivityManagerNative.getDefault().registerReceiver(mMainThread.getApplicationThread(), mBasePackageName,rd, filter, broadcastPermission, userId);//4if (intent != null) {intent.setExtrasClassLoader(getClassLoader());intent.prepareToEnterProcess();}return intent;} catch (RemoteException e) {throw e.rethrowFromSystemServer();} View Code

在注釋1處判斷如果LoadedApk類型的mPackageInfo不等于null并且context不等null就調(diào)用注釋2處的代碼通過mPackageInfo的getReceiverDispatcher方法獲取rd對象,否則就調(diào)用注釋3處的代碼來創(chuàng)建rd對象。注釋2和3的代碼的目的都是要獲取IIntentReceiver類型的rd對象,IIntentReceiver是一個(gè)Binder接口,用于進(jìn)行跨進(jìn)程的通信,它的具體實(shí)現(xiàn)在
LoadedApk.ReceiverDispatcher.InnerReceiver,如下所示。

frameworks/base/core/java/android/app/LoadedApk.java

static final class ReceiverDispatcher {final static class InnerReceiver extends IIntentReceiver.Stub {final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;final LoadedApk.ReceiverDispatcher mStrongRef;InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);mStrongRef = strong ? rd : null;}... }... } View Code

回到registerReceiverInternal方法,在注釋4處調(diào)用了ActivityManagerProxy(AMP)的registerReceiver方法,最終會調(diào)用AMS的registerReceiver方法,并將rd傳就去。不明白的同學(xué)請查看Android深入四大組件(一)應(yīng)用程序啟動過程(前篇),這里不再贅述。
查看AMS的registerReceiver方法,如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public Intent registerReceiver(IApplicationThread caller, String callerPackage,IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { ...synchronized(this) {...Iterator<String> actions = filter.actionsIterator();//1 ...// Collect stickies of usersint[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };while (actions.hasNext()) {String action = actions.next();for (int id : userIds) {ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);if (stickies != null) {ArrayList<Intent> intents = stickies.get(action);if (intents != null) {if (stickyIntents == null) {stickyIntents = new ArrayList<Intent>();}stickyIntents.addAll(intents);//2 }}}}}ArrayList<Intent> allSticky = null; if (stickyIntents != null) {final ContentResolver resolver = mContext.getContentResolver();for (int i = 0, N = stickyIntents.size(); i < N; i++) {Intent intent = stickyIntents.get(i);if (filter.match(resolver, intent, true, TAG) >= 0) {if (allSticky == null) {allSticky = new ArrayList<Intent>();}allSticky.add(intent);//3 }}}... } View Code

注釋1處根據(jù)傳入的IntentFilter類型的filter的得到actions列表,根據(jù)actions列表和userIds(userIds可以理解為應(yīng)用程序的uid)得到所有的粘性廣播的intent,并在注釋2處傳入到stickyIntents中,在注釋3處將這些粘性廣播的intent存入到allSticky列表中,從這里可以看出粘性廣播是存儲在AMS中的。
接著查看AMS的registerReceiver方法的剩余內(nèi)容:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public Intent registerReceiver(IApplicationThread caller, String callerPackage,IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { ...synchronized (this) {...ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());//1if (rl == null) {rl = new ReceiverList(this, callerApp, callingPid, callingUid,userId, receiver);//2if (rl.app != null) {rl.app.receivers.add(rl);} ...}...BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,permission, callingUid, userId);//3rl.add(bf);//4if (!bf.debugCheck()) {Slog.w(TAG, "==> For Dynamic broadcast");}mReceiverResolver.addFilter(bf);//5 ...return sticky;} } View Code

注釋1處獲取ReceiverList列表,如果為空則在注釋2處創(chuàng)建,ReceiverList繼承自ArrayList,用來存儲廣播接收者。在注釋3處創(chuàng)建BroadcastFilter并傳入此前創(chuàng)建的ReceiverList,BroadcastFilter用來描述注冊的廣播接收者,并在注釋4通過add方法將自身添加到ReceiverList中。注釋5處將BroadcastFilter添加到mReceiverResolver中,這樣當(dāng)AMS接收到廣播時(shí)就可以從mReceiverResolver中找到對應(yīng)的廣播接收者了。下面給出廣播的注冊過程的時(shí)序圖。

繪圖1_副本.png

2.廣播的發(fā)送和接收過程

ContextImpl到AMS的調(diào)用過程

廣播可以發(fā)送多種類型,包括無序廣播(普通廣播)、有序廣播和粘性廣播,這里以無序廣播為例,來講解廣播的發(fā)送過程。
要發(fā)送無序廣播需要調(diào)用sendBroadcast方法,它的實(shí)現(xiàn)同樣在ContextWrapper中:
frameworks/base/core/java/android/content/ContextWrapper.java

@Overridepublic void sendBroadcast(Intent intent) {mBase.sendBroadcast(intent);} View Code

接著來看ContextImpl中的sendBroadcast方法,如下所示。
frameworks/base/core/java/android/app/ContextImpl.java

@Overridepublic void sendBroadcast(Intent intent) {warnIfCallingFromSystemProcess();String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());try {intent.prepareToLeaveProcess(this);ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null,Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,getUserId());//1} catch (RemoteException e) {throw e.rethrowFromSystemServer();}} View Code

注釋1處又是熟悉的代碼,最終會調(diào)用AMS的broadcastIntent方法:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public final int broadcastIntent(IApplicationThread caller,Intent intent, String resolvedType, IIntentReceiver resultTo,int resultCode, String resultData, Bundle resultExtras,String[] requiredPermissions, int appOp, Bundle bOptions,boolean serialized, boolean sticky, int userId) {enforceNotIsolatedCaller("broadcastIntent");synchronized(this) {intent = verifyBroadcastLocked(intent);//1 .../*** 2*/int res = broadcastIntentLocked(callerApp,callerApp != null ? callerApp.info.packageName : null,intent, resolvedType, resultTo, resultCode, resultData, resultExtras,requiredPermissions, appOp, bOptions, serialized, sticky,callingPid, callingUid, userId);Binder.restoreCallingIdentity(origId);return res;}} View Code

我們來查看注釋1處的verifyBroadcastLocked方法:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

final Intent verifyBroadcastLocked(Intent intent) {// Refuse possible leaked file descriptorsif (intent != null && intent.hasFileDescriptors() == true) {//1throw new IllegalArgumentException("File descriptors passed in Intent");}int flags = intent.getFlags();//2if (!mProcessesReady) {if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {//3} else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {//4Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent+ " before boot completion");throw new IllegalStateException("Cannot broadcast before boot completed");}}if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {throw new IllegalArgumentException("Can't use FLAG_RECEIVER_BOOT_UPGRADE here");}return intent;} View Code

verifyBroadcastLocked方法主要是驗(yàn)證廣播是否合法,在注釋1處驗(yàn)證intent是否不為null并且有文件描述符。注釋2處獲得intent中的flag。注釋3處如果系統(tǒng)正在啟動過程中,判斷如果flag設(shè)置為FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT(啟動檢查時(shí)只接受動態(tài)注冊的廣播接收者)則不做處理,如果不是則在注釋4處判斷如果flag沒有設(shè)置為FLAG_RECEIVER_REGISTERED_ONLY(只接受動態(tài)注冊的廣播接收者)則會拋出異常。
我們再回到broadcastIntent方法,在注釋2處調(diào)用了broadcastIntentLocked方法,代碼如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

final int broadcastIntentLocked(ProcessRecord callerApp,String callerPackage, Intent intent, String resolvedType,IIntentReceiver resultTo, int resultCode, String resultData,Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {...if ((receivers != null && receivers.size() > 0)|| resultTo != null) {BroadcastQueue queue = broadcastQueueForIntent(intent);/*** 1*/BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,callerPackage, callingPid, callingUid, resolvedType,requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,resultData, resultExtras, ordered, sticky, false, userId);... boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);if (!replaced) {queue.enqueueOrderedBroadcastLocked(r);queue.scheduleBroadcastsLocked();//2 }} ...}return Act View Code

這里省略了很多代碼,前面的工作主要是將動態(tài)注冊的廣播接收者和靜態(tài)注冊的廣播接收者按照優(yōu)先級高低存儲在不同的列表中,再將這兩個(gè)列表合并到receivers列表中,這樣receivers列表包含了所有的廣播接收者(無序廣播和有序廣播)。在注釋1處創(chuàng)建BroadcastRecord對象并將receivers傳進(jìn)去,在注釋2處調(diào)用BroadcastQueue的scheduleBroadcastsLocked方法。
這里先給出ContextImpl到AMS的調(diào)用過程的時(shí)序圖。

繪圖8_副本.png

AMS到BroadcastReceiver的調(diào)用過程

BroadcastQueue的scheduleBroadcastsLocked方法的代碼如下所示。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

public void scheduleBroadcastsLocked() { ...mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));//1mBroadcastsScheduled = true; } View Code

在注釋1處向BroadcastHandler類型的mHandler對象發(fā)送了BROADCAST_INTENT_MSG類型的消息,這個(gè)消息在BroadcastHandler的handleMessage方法中進(jìn)行處理,如下所示。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

private final class BroadcastHandler extends Handler {public BroadcastHandler(Looper looper) {super(looper, null, true);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case BROADCAST_INTENT_MSG: {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");processNextBroadcast(true);} break;...}} } View Code

在handleMessage方法中調(diào)用了processNextBroadcast方法,processNextBroadcast方法對無序廣播和有序廣播分別進(jìn)行處理,旨在將廣播發(fā)送給廣播接收者,下面給出processNextBroadcast方法中對無序廣播的處理部分。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

final void processNextBroadcast(boolean fromMsg) { ...if (fromMsg) {mBroadcastsScheduled = false;//1 }// First, deliver any non-serialized broadcasts right away.while (mParallelBroadcasts.size() > 0) {//2r = mParallelBroadcasts.remove(0);//3 ...for (int i=0; i<N; i++) {Object target = r.receivers.get(i);if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Delivering non-ordered on [" + mQueueName + "] to registered "+ target + ": " + r);deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);//4 }...} } View Code

從前面的代碼我們得知fromMsg的值為true,因此注釋1處會將mBroadcastsScheduled 設(shè)置為flase,表示對于此前發(fā)來的BROADCAST_INTENT_MSG類型的消息已經(jīng)處理了。注釋2處的mParallelBroadcasts列表用來存儲無序廣播,通過while循環(huán)將mParallelBroadcasts列表中的無序廣播發(fā)送給對應(yīng)的廣播接收者。在注釋3處獲取每一個(gè)mParallelBroadcasts列表中存儲的BroadcastRecord類型的r對象。注釋4處將這些r對象描述的廣播發(fā)送給對應(yīng)的廣播接收者,deliverToRegisteredReceiverLocked方法如下所示。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,BroadcastFilter filter, boolean ordered, int index) { ...try {if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,"Delivering to " + filter + " : " + r);if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {... } else {performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,new Intent(r.intent), r.resultCode, r.resultData,r.resultExtras, r.ordered, r.initialSticky, r.userId);//1 }if (ordered) {r.state = BroadcastRecord.CALL_DONE_RECEIVE;}} catch (RemoteException e) {...}} View Code

這里省去了大部分的代碼,這些代碼是用來檢查廣播發(fā)送者和廣播接收者的權(quán)限。如果通過了權(quán)限的檢查,則會調(diào)用注釋1處的performReceiveLocked方法:
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,Intent intent, int resultCode, String data, Bundle extras,boolean ordered, boolean sticky, int sendingUser) throws RemoteException {// Send the intent to the receiver asynchronously using one-way binder calls.if (app != null) {//1if (app.thread != null) {//2// If we have an app thread, do the call through that so it is// correctly ordered with other one-way calls.try {app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,data, extras, ordered, sticky, sendingUser, app.repProcState);//3 } } ...} else {receiver.performReceive(intent, resultCode, data, extras, ordered,sticky, sendingUser);/}} View Code

注釋1和2處的代碼表示如果廣播接收者所在的應(yīng)用程序進(jìn)程存在并且正在運(yùn)行,則執(zhí)行注釋3處的代碼,表示用廣播接收者所在的應(yīng)用程序進(jìn)程來接收廣播,這里app.thread指的是ApplicationThread,我們來查看ApplicationThread的scheduleRegisteredReceiver方法,代碼如下所示。
frameworks/base/core/java/android/app/ActivityThread.java

public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,int resultCode, String dataStr, Bundle extras, boolean ordered,boolean sticky, int sendingUser, int processState) throws RemoteException {updateProcessState(processState, false);receiver.performReceive(intent, resultCode, dataStr, extras, ordered,sticky, sendingUser);//1} View Code

注釋1處調(diào)用了IIntentReceiver類型的對象receiver的performReceive方法,這里實(shí)現(xiàn)receiver的類為LoadedApk.ReceiverDispatcher.InnerReceiver,代碼如下所示。
frameworks/base/core/java/android/app/LoadedApk.java

static final class ReceiverDispatcher {final static class InnerReceiver extends IIntentReceiver.Stub {...InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);mStrongRef = strong ? rd : null;}@Overridepublic void performReceive(Intent intent, int resultCode, String data,Bundle extras, boolean ordered, boolean sticky, int sendingUser) {final LoadedApk.ReceiverDispatcher rd;...if (rd != null) {rd.performReceive(intent, resultCode, data, extras,ordered, sticky, sendingUser);//1} else {...} ... } View Code

在注釋1處調(diào)用了ReceiverDispatcher類型的rd對象的performReceive方法:
frameworks/base/core/java/android/app/LoadedApk.java

public void performReceive(Intent intent, int resultCode, String data,Bundle extras, boolean ordered, boolean sticky, int sendingUser) {final Args args = new Args(intent, resultCode, data, extras, ordered,sticky, sendingUser);//1 ...if (intent == null || !mActivityThread.post(args)) {//2if (mRegistered && ordered) {IActivityManager mgr = ActivityManagerNative.getDefault();if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,"Finishing sync broadcast to " + mReceiver);args.sendFinished(mgr);}} View Code

在注釋1處將廣播的intent等信息封裝為Args對象,并在注釋2處調(diào)用mActivityThread的post方法并傳入了Args對象。這個(gè)mActivityThread是一個(gè)Handler對象,具體指向的就是H,注釋2處的代碼就是將Args對象通過H發(fā)送到主線程的消息隊(duì)列中。Args繼承自Runnable,這個(gè)消息最終會在Args的run方法執(zhí)行,Args的run方法如下所示。

frameworks/base/core/java/android/app/LoadedApk.java

public void run() {...try {ClassLoader cl = mReceiver.getClass().getClassLoader();intent.setExtrasClassLoader(cl);intent.prepareToEnterProcess();setExtrasClassLoader(cl);receiver.setPendingResult(this);receiver.onReceive(mContext, intent);//1} catch (Exception e) {...}...} View Code

在注釋1處執(zhí)行了廣播接收者的onReceive方法,這樣注冊的廣播接收者就收到了廣播并得到了intent。
廣播的注冊、發(fā)送和接收過程就講到這,最后給出剩余部分的調(diào)用時(shí)序圖。

?

轉(zhuǎn)載于:https://www.cnblogs.com/ganchuanpu/p/8597397.html

總結(jié)

以上是生活随笔為你收集整理的Android深入四大组件(八)广播的注册、发送和接收过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美在线一区二区三区 | 特级特黄刘亦菲aaa级 | 无码精品一区二区三区在线播放 | 国产在线一区二区 | 人妻无码中文久久久久专区 | 日本高清不卡一区 | 免费在线观看av片 | 欧美一区二区三区电影 | 97超碰总站| 日本高清视频一区二区三区 | 国产免费福利视频 | 久久久久成人精品免费播放动漫 | 男人天堂影院 | 6080午夜伦理 | 高潮网| 爱爱精品| 芒果视频污污 | 色播放| 亚洲中文字幕无码专区 | 麻豆亚洲av熟女国产一区二 | 日本少妇高潮 | 特黄色大片 | 可以免费观看av的网站 | 中文字幕高清 | 干美女视频 | 穿扒开跪着折磨屁股视频 | 亚洲另类色综合网站 | 国产在线不卡一区 | 亚洲一区二区精华 | 国产免费脚交足视频在线观看 | 少妇自摸视频 | 欧美黄一级 | 免费黄色激情视频 | 天天综合网国产 | 亚洲天堂中文在线 | 亚洲av永久中文无码精品综合 | 亚洲欧美国产高清 | www国产黄色| 国产在线视频卡一卡二 | 新超碰97| 无码国产精品高潮久久99 | 黄色一级片在线播放 | 日本zzjj | aaaaa毛片| 国产最爽的乱淫视频国语对白 | 国产无码精品久久久 | 日韩欧美成| 毛片无码一区二区三区a片视频 | 大学生一级一片全黄 | brazzers欧美大波霸 | 久久综合九色综合欧美狠狠 | av中文一区 | 国产精品a级 | 国产一级α片 | 欧美精品亚洲一区 | 欧美黑人一级 | 久久久久久一区二区三区 | 欧美成本人视频 | 欧美亚色| 国产第6页 | 99re超碰| 精品久久久久久久久久久久久 | 精品动漫一区二区三区的观看方式 | 综合人人| va免费视频 | 久久av一区 | 8x国产一区二区三区精品推荐 | 欧洲丰满少妇做爰 | 综合精品久久 | 久久精品国产99精品国产亚洲性色 | mm1313亚洲国产精品无码试看 | 黄色av一区二区三区 | 美女xx00| 色欲av无码一区二区三区 | 99精品视频免费版的特色功能 | 69色综合 | 国内精品999 | 久久9热 | 日韩精品一区二区在线视频 | 一个人在线观看www软件 | 高清一区二区三区四区 | 成人免费影视网站 | 成年人网站免费看 | 国产suv精品一区二区 | 粉豆av| 91在线视频导航 | 色综合久久网 | 欧美一区日韩一区 | 国产精品乱码 | a级成人毛片 | 色综合网站 | 97少妇| 人人草人人 | 成人免费看高清电影在线观看 | 99久久精品免费看 | 久久免费黄色网址 | 久久888 | 亚洲女人毛片 | 99精品视频在线免费观看 |