日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android应用程序资源管理器(Asset Manager)的创建过程分析

發布時間:2024/1/1 Android 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android应用程序资源管理器(Asset Manager)的创建过程分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? 在前面一篇文章中,我們分析了Android應用程序資源的編譯和打包過程,最終得到的應用程序資源就與應用程序代碼一起打包在一個APK文件中。Android應用程序在運行的過程中,是通過一個稱為AssetManager的資源管理器來讀取打包在APK文件里面的資源文件的。在本文中,我們就將詳細分析Android應用程序資源管理器的創建以及初始化過程,為接下來的一篇文章分析應用程序資源的讀取過程打下基礎。

《Android系統源代碼情景分析》一書正在進擊的程序員網(http://0xcc0xcd.com)中連載,點擊進入!

? ? ? ? 從前面Android應用程序窗口(Activity)的運行上下文環境(Context)的創建過程分析一文可以知道,應用程序的每一個Activity組件都關聯有一個ContextImpl對象,這個ContextImpl對象就是用來描述Activity組件的運行上下文環境的。Activity組件是從Context類繼承下來的,而ContextImpl同樣是從Context類繼承下來的。我們在Activity組件調用的大部分成員函數都是轉發給與它所關聯的一個ContextImpl對象的對應的成員函數來處理的,其中就包括用來訪問應用程序資源的兩個成員函數getResources和getAssets。

? ? ? ??ContextImpl類的成員函數getResources返回的是一個Resources對象,有了這個Resources對象之后,我們就可以通過資源ID來訪問那些被編譯過的應用程序資源了。ContextImpl類的成員函數getAssets返回的是一個AssetManager對象,有了這個AssetManager對象之后,我們就可以通過文件名來訪問那些被編譯過或者沒有被編譯過的應用程序資源文件了。事實上,Resources類也是通過AssetManager類來訪問那些被編譯過的應用程序資源文件的,不過在訪問之前,它會先根據資源ID查找得到對應的資源文件名。

? ? ? ? 我們知道,在Android系統中,一個進程是可以同時加載多個應用程序的,也就是可以同時加載多個APK文件。每一個APK文件在進程中都對應有一個全局的Resourses對象以及一個全局的AssetManager對象。其中,這個全局的Resourses對象保存在一個對應的ContextImpl對象的成員變量mResources中,而這個全局的AssetManager對象保存在這個全局的Resourses對象的成員變量mAssets中。上述ContextImpl、Resourses和AssetManager的關系如圖1所示:


圖1 ContextImpl、Resources和AssetManager的關系圖

? ? ? ? Resources類有一個成員函數getAssets,通過它就可以獲得保存在Resources類的成員變量mAssets中的AssetManager,例如,ContextImpl類的成員函數getAssets就是通過調用其成員變量mResources所指向的一個Resources對象的成員函數getAssets來獲得一個可以用來訪問應用程序的非編譯資源文件的AssetManager。

? ? ? ? 我們知道,Android應用程序除了要訪問自己的資源之外,還需要訪問系統的資源。系統的資源打包在/system/framework/framework-res.apk文件中,它在應用程序進程中是通過一個單獨的Resources對象和一個單獨的AssetManager對象來管理的。這個單獨的Resources對象就保存在Resources類的靜態成員變量mSystem中,我們可以通過Resources類的靜態成員函數getSystem就可以獲得這個Resources對象,而這個單獨的AssetManager對象就保存在AssetManager類的靜態成員變量sSystem中,我們可以通過AssetManager類的靜態成員函數getSystem同樣可以獲得這個AssetManager對象。

? ? ? ? AssetManager類除了在Java層有一個實現之外,在 C++層也有一個對應的實現,而Java層的AssetManager類的功能就是通過C++層的AssetManager類來實現的。Java層的每一個AssetManager對象都有一個類型為int的成員變量mObject,它保存的便是在C++層對應的AssetManager對象的地址,因此,通過這個成員變量就可以將Java層的AssetManager對象與C++層的AssetManager對象關聯起來。

? ? ? ? C++層的AssetManager類有三個重要的成員變量mAssetPaths、mResources和mConfig。其中,mAssetPaths保存的是資源存放目錄,mResources指向的是一個資源索引表,而mConfig保存的是設備的本地配置信息,例如屏幕密度和大小、國家地區和語言等等配置信息。有了這三個成員變量之后,C++層的AssetManager類就可以訪問應用程序的資源了。

? ? ? ? 從前面Android應用程序啟動過程源代碼分析一文可以知道,每一個Activity組件在進程的加載過程中,都會創建一個對應的ContextImpl,并且調用這個ContextImpl對象的成員函數init來執行初始化Activity組件運行上下文環境的工作,其中就包括創建用來訪問應用程序資源的Resources對象和AssetManager對象的工作,接下來,我們就從ContextImpl類的成員函數init開始分析Resources對象和AssetManager對象的創建以及初始化過程,如圖2所示:

圖2 應用程序資源管理器的創建和初始化過程

? ? ? ? 這個過程可以分為14個步驟,接下來我們就詳細分析每一個步驟。

? ? ? ? Step 1. ContextImpl.init

class ContextImpl extends Context {....../*package*/ LoadedApk mPackageInfo;private Resources mResources;......final void init(LoadedApk packageInfo,IBinder activityToken, ActivityThread mainThread) {init(packageInfo, activityToken, mainThread, null);}final void init(LoadedApk packageInfo,IBinder activityToken, ActivityThread mainThread,Resources container) {mPackageInfo = packageInfo;mResources = mPackageInfo.getResources(mainThread);......}...... }

? ? ? ? 這個函數定義在文件frameworks/base/core/java/android/app/ContextImpl.java中。

? ? ? ? 參數packageInfo指向的是一個LoadedApk對象,這個LoadedApk對象描述的是當前正在啟動的Activity組所屬的Apk。三個參數版本的成員函數init調用了四個參數版本的成員函數init來初始化當前正在啟動的Activity組件的運行上下文環境。其中,用來訪問應用程序資源的Resources對象是通過調用參數packageInfo所指向的是一個LoadedApk對象的成員函數getResources來創建的。這個Resources對象創建完成之后,就會保存在ContextImpl類的成員變量mResources中。

? ? ? ? 接下來,我們就繼續分析LoadedApk類的成員函數getResources的實現。

? ? ? ? Step 2.?LoadedApk.getResources

final class LoadedApk {......private final String mResDir;......Resources mResources;......public Resources getResources(ActivityThread mainThread) {if (mResources == null) {mResources = mainThread.getTopLevelResources(mResDir, this);}return mResources;}...... }? ? ? ? 這個函數定義在文件frameworks/base/core/java/android/app/LoadedApk.java中。

? ? ? ? 參數mainThread指向了一個ActivityThread對象,這個ActivityThread對象描述的是當前正在運行的應用程序進程。

? ? ? ? LoadedApk類的成員函數getResources首先檢查其成員變量mResources的值是否等于null。如果不等于的話,那么就會將它所指向的是一個Resources對象返回給調用者,否則的話,就會調用參數mainThread所指向的一個ActivityThread對象的成員函數getTopLevelResources來獲得這個Resources對象,然后再返回給調用者。

? ? ? ? 在調用ActivityThread類的成員函數getTopLevelResources來獲得一個Resources對象的時候,需要指定要獲取的Resources對象所對應的Apk文件路徑,這個Apk文件路徑就保存在LoadedApk類的成員變量mResDir中。例如,假設我們要獲取的Resources對象是用來訪問系統自帶的音樂播放器的資源的,那么對應的Apk文件路徑就為/system/app/Music.apk。

? ? ? ? 接下來,我們就繼續分析ActivityThread類的成員函數getTopLevelResources的實現。

? ? ? ? Step 3.?ActivityThread.getTopLevelResources

public final class ActivityThread {......final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources= new HashMap<ResourcesKey, WeakReference<Resources> >();......Resources getTopLevelResources(String resDir, CompatibilityInfo compInfo) {ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale);Resources r;synchronized (mPackages) {......WeakReference<Resources> wr = mActiveResources.get(key);r = wr != null ? wr.get() : null;......if (r != null && r.getAssets().isUpToDate()) {......return r;}}......AssetManager assets = new AssetManager();if (assets.addAssetPath(resDir) == 0) {return null;}......r = new Resources(assets, metrics, getConfiguration(), compInfo);......synchronized (mPackages) {WeakReference<Resources> wr = mActiveResources.get(key);Resources existing = wr != null ? wr.get() : null;if (existing != null && existing.getAssets().isUpToDate()) {// Someone else already created the resources while we were// unlocked; go ahead and use theirs.r.getAssets().close();return existing;}// XXX need to remove entries when weak references go awaymActiveResources.put(key, new WeakReference<Resources>(r));return r;}}...... }? ? ? ? 這個函數定義在文件frameworks/base/core/java/android/app/ActivityThread.java中。

? ? ? ??ActivityThread類的成員變量mActiveResources指向的是一個HashMap。這個HashMap用來維護在當前應用程序進程中加載的每一個Apk文件及其對應的Resources對象的對應關系。也就是說,給定一個Apk文件路徑,ActivityThread類的成員函數getTopLevelResources可以在成員變量mActiveResources中檢查是否存在一個對應的Resources對象。如果不存在,那么就會新建一個,并且保存在ActivityThread類的成員變量mActiveResources中。

? ? ? ? 參數resDir即為要獲取其對應的Resources對象的Apk文件路徑,ActivityThread類的成員函數getTopLevelResources首先根據它來創建一個ResourcesKey對象,然后再以這個ResourcesKey對象在ActivityThread類的成員變量mActiveResources中檢查是否存在一個Resources對象。如果存在,并且這個Resources對象里面包含的資源文件沒有過時,即調用這個Resources對象的成員函數getAssets所獲得一個AssetManager對象的成員函數isUpToDate的返回值等于true,那么ActivityThread類的成員函數getTopLevelResources就可以將該Resources對象返回給調用者了。

? ? ? ? 如果不存在與參數resDir對應的Resources對象,或者存在這個Resources對象,但是存在的這個Resources對象是過時的,那么ActivityThread類的成員函數getTopLevelResources就會新創建一個AssetManager對象,并且調用這個新創建的AssetManager對象的成員函數addAssetPath來將參數resDir所描述的Apk文件路徑作為它的資源目錄。

? ? ? ? 創建了一個新的AssetManager對象,ActivityThread類的成員函數getTopLevelResources還需要這個AssetManager對象來創建一個新的Resources對象。這個新創建的Resources對象需要以前面所創建的ResourcesKey對象為鍵值緩存在ActivityThread類的成員變量mActiveResources所描述的一個HashMap中,以便以后可以獲取回來使用。不過,這個新創建的Resources對象在緩存到ActivityThread類的成員變量mActiveResources所描述的一個HashMap去之前,需要再次檢查該HashMap是否已經存在一個對應的Resources對象了,這是因為當前線程在創建新的AssetManager對象和Resources對象的過程中,可能有其它線程搶先一步創建了與參數resDir對應的Resources對象,并且將該Resources對象保存到該HashMap中去了。

? ? ? ? 如果沒有其它線程搶先創建一個與參數resDir對應的Resources對象,或者其它線程搶先創建出來的Resources對象是過時的,那么ActivityThread類的成員函數getTopLevelResources就會將前面創建的Resources對象緩存到成員變量mActiveResources所描述的一個HashMap中去,并且將前面創建的Resources對象返回給調用者,否則擴知,就會將其它線程搶先創建的Resources對象返回給調用者。

? ? ? ? 接下來,我們首先分析AssetManager類的構造函數和成員函數addAssetPath的實現,接著再分析Resources類的構造函數的實現,以便可以了解用來訪問應用程序資源的AssetManager對象和Resources對象的創建以及初始化過程。

? ? ? ? Step 4. new?AssetManager

public final class AssetManager {......private static AssetManager sSystem = null;......public AssetManager() {synchronized (this) {......init();......ensureSystemAssets();}}private static void ensureSystemAssets() {synchronized (sSync) {if (sSystem == null) {AssetManager system = new AssetManager(true);system.makeStringBlocks(false);sSystem = system;}}}...... }? ? ? ? 這個函數定義在文件frameworks/base/core/java/android/content/res/AssetManager.java中。

? ? ? ??AssetManager類的構造函數是通過調用另外一個成員函數init來執行初始化工作的。在初始化完成當前正在創建的AssetManager對象之后,AssetManager類的構造函數還會調用另外一個成員函數ensureSystemAssets來檢查當前進程是否已經創建了一個用來訪問系統資源的AssetManager對象。

? ? ? ? 如果用來訪問系統資源的AssetManager對象還沒有創建的話,那么AssetManager類的成員函數ensureSystemAssets就會創建并且初始化它,并且將它保存在AssetManager類的靜態成員變量sSystem中。注意,創建用來訪問系統資源和應用程序資源的AssetManager對象的過程是一樣的,區別只在于它們所要訪問的Apk文件不一樣,因此,接下來我們就只分析用來訪問應用資源的AssetManager對象的創建過程以及初始化過程。

? ? ? ?Step 5.?AssetManager.init

public final class AssetManager {......private int mObject;......private native final void init();...... }

? ? ? ?這個函數定義在文件frameworks/base/core/java/android/content/res/AssetManager.java中。

? ? ? ?AssetManager類的成員函數init是一個JNI函數,它是由C++層的函數android_content_AssetManager_init來實現的:

static void android_content_AssetManager_init(JNIEnv* env, jobject clazz) {AssetManager* am = new AssetManager();.....am->addDefaultAssets();......env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am); }? ? ? ? ?這個函數定義在文件frameworks/base/core/jni/android_util_AssetManager.cpp中。

? ? ? ? ?函數android_content_AssetManager_init首先創建一個C++層的AssetManager對象,接著調用這個C++層的AssetManager對象的成員函數addDefaultAssets來添加默認的資源路徑,最后將這個這個C++層的AssetManager對象的地址保存在參數clazz所描述的一個Java層的AssetManager對象的成員變量mObject中。

? ? ? ? Step 6.?AssetManager.addDefaultAssets

static const char* kSystemAssets = "framework/framework-res.apk"; ......bool AssetManager::addDefaultAssets() {const char* root = getenv("ANDROID_ROOT");......String8 path(root);path.appendPath(kSystemAssets);return addAssetPath(path, NULL); }? ? ? ?這個函數定義在文件frameworks/base/libs/utils/AssetManager.cpp中。

? ? ? ?AssetManager類的成員函數addDefaultAssets首先通過環境變量ANDROID_ROOT來獲得Android的系統路徑,接著再將全局變量kSystemAssets所指向的字符串“framework/framework-res.apk”附加到這個系統路徑的后面去,這樣就可以得到系統資源文件framework-res.apk的絕對路徑了。一般來說,環境變量ANDROID_ROOT所設置的Android系統路徑就是“/system”,因此,最終得到的系統資源文件的絕對路徑就為“/system/framework/framework-res.apk”。

? ? ? ?得到了系統資源文件framework-res.apk的絕對路徑之后,就調用AssetManager類的成員函數addAssetPath來將它添加到當前正在初始化的AssetManager對象中去。

? ? ? ?Step 7.?AssetManager.addAssetPath

static const char* kAppZipName = NULL; //"classes.jar"; ......bool AssetManager::addAssetPath(const String8& path, void** cookie) {AutoMutex _l(mLock);asset_path ap;String8 realPath(path);if (kAppZipName) {realPath.appendPath(kAppZipName);}ap.type = ::getFileType(realPath.string());if (ap.type == kFileTypeRegular) {ap.path = realPath;} else {ap.path = path;ap.type = ::getFileType(path.string());if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) {......return false;}}// Skip if we have it already.for (size_t i=0; i<mAssetPaths.size(); i++) {if (mAssetPaths[i].path == ap.path) {if (cookie) {*cookie = (void*)(i+1);}return true;}}......mAssetPaths.add(ap);// new paths are always added at the endif (cookie) {*cookie = (void*)mAssetPaths.size();}// add overlay packages for /system/framework; apps are handled by the// (Java) package managerif (strncmp(path.string(), "/system/framework/", 18) == 0) {// When there is an environment variable for /vendor, this// should be changed to something similar to how ANDROID_ROOT// and ANDROID_DATA are used in this file.String8 overlayPath("/vendor/overlay/framework/");overlayPath.append(path.getPathLeaf());if (TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK)) == 0) {asset_path oap;oap.path = overlayPath;oap.type = ::getFileType(overlayPath.string());bool addOverlay = (oap.type == kFileTypeRegular); // only .apks supported as overlayif (addOverlay) {oap.idmap = idmapPathForPackagePath(overlayPath);if (isIdmapStaleLocked(ap.path, oap.path, oap.idmap)) {addOverlay = createIdmapFileLocked(ap.path, oap.path, oap.idmap);}}if (addOverlay) {mAssetPaths.add(oap);} ......}}return true; }? ? ? ? 這個函數定義在文件frameworks/base/libs/utils/AssetManager.cpp中。

? ? ? ? 如果全局變量kAppZipName的值不等于NULL的話,那么它的值一般就是被設置為“classes.jar”,這時候就表示應用程序的資源文件是保存在參數path所描述的一個目錄下的一個classes.jar文件中。全局變量kAppZipName的值一般被設置為NULL,并且參數path指向的是一個Apk文件,因此,接下來我們只考慮應用程序資源不是保存在一個classes.jar文件的情況。

? ? ? ??AssetManager類的成員函數addAssetPath首先是要檢查參數path指向的是一個文件或者目錄,并且該文件或者目錄存在,否則的話,它就會直接返回一個false值,而不會再繼續往下處理了。

? ? ? ??AssetManager類的成員函數addAssetPath接著再檢查在其成員變量mAssetPaths所描述的一個類型為asset_path的Vector中是否已經添加過參數path所描述的一個Apk文件路徑了。如果已經添加過了,那么AssetManager類的成員函數addAssetPath就不會再繼續往下處理了,而是將與參數path所描述的一個Apk文件路徑所對應的一個Cookie返回給調用者,即保存在輸出參數cookie中,前提是參數cookie的值不等于NULL。一個Apk文件路徑所對應的Cookie實際上只是一個整數,這個整數表示該Apk文件路徑所對應的一個asset_path對象在成員變量mAssetPaths所描述的一個Vector中的索引再加上1。

? ? ? ? 經過上面的檢查之后,AssetManager類的成員函數addAssetPath確保參數path所描述的一個Apk文件路徑之前沒有被添加過,于是接下來就會將與該Apk文件路徑所對應的一個asset_path對象保存在成員變量mAssetPaths所描述的一個Vector的最末尾位置上,并且將這時候得到的Vector的大小作為一個Cookie值保存在輸出參數cookie中返回給調用者。

? ? ? ??AssetManager類的成員函數addAssetPath的最后一個工作是檢查剛剛添加的Apk文件路徑是否是保存在/system/framework/目錄下面的。如果是的話,那么就會在/vendor/overlay/framework/目錄下找到一個同名的Apk文件,并且也會將該Apk文件添加到成員變量mAssetPaths所描述的一個Vector中去。這是一種資源覆蓋機制,手機廠商可以利用它來自定義的系統資源,即用自定義的系統資源來覆蓋系統默認的系統資源,以達到個性化系統界面的目的。

? ? ? ? 如果手機廠商要利用上述的資源覆蓋機制來自定義自己的系統資源,那么還需要提供一個idmap文件,用來說明它在/vendor/overlay/framework/目錄提供的Apk文件要覆蓋系統的哪些默認資源,使用資源ID來描述,因此,這個idmap文件實際上就是一個資源ID映射文件。這個idmap文件最終保存在/data/resource-cache/目錄下,并且按照一定的格式來命令,例如,假設手機廠商提供的覆蓋資源文件為/vendor/overlay/framework/framework-res.apk,那么對應的idmap文件就會以名稱為@vendor@overlay@framework@framework-res.apk@idmap的形式保存在目錄/data/resource-cache/下。

? ? ? ? 關于Android系統的資源覆蓋(Overlay)機制,可以參考frameworks/base/libs/utils目錄下的READ文件。

? ? ? ? 這一步執行完成之后,回到前面的Step 3中,即ActivityThread類的成員函數getTopLevelResources中,接下來它就會調用前面所創建的Java層的AssetManager對象的成員函數addAssetPath來添加指定的應用程序資源文件路徑。

? ? ? ? Step 8.?AssetManager.addAssetPath

public final class AssetManager {....../*** Add an additional set of assets to the asset manager. This can be* either a directory or ZIP file. Not for use by applications. Returns* the cookie of the added asset, or 0 on failure.* {@hide}*/public native final int addAssetPath(String path);...... }

? ? ? ? 這個函數定義在文件frameworks/base/core/java/android/content/res/AssetManager.java中。

? ? ? ??AssetManager類的成員函數addAssetPath是一個JNI方法,它是由C++層的函數android_content_AssetManager_addAssetPath來實現的,如下所示:

static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,jstring path) {......AssetManager* am = assetManagerForJavaObject(env, clazz);......const char* path8 = env->GetStringUTFChars(path, NULL);void* cookie;bool res = am->addAssetPath(String8(path8), &cookie);env->ReleaseStringUTFChars(path, path8);return (res) ? (jint)cookie : 0; }? ? ? ? 這個函數定義在文件frameworks/base/core/jni/android_util_AssetManager.cpp中。

? ? ? ? 參數clazz指向的是Java層的一個AssetManager對象,函數android_content_AssetManager_addAssetPath首先調用另外一個函數assetManagerForJavaObject來將它的成員函數mObject轉換為一個C++層的AssetManager對象。有了這個C++層的AssetManager對象之后,就可以調用它的成員函數addAssetPath來將參數path所描述的一個Apk文件路徑添加到它里面去了,這個過程可以參考前面的Step 7。

? ? ? ? 這一步執行完成之后,回到前面的Step 3中,即ActivityThread類的成員函數getTopLevelResources中,接下來就會根據前面所創建的Java層的AssetManager對象來創建一個Resources對象。

? ? ? ? Step 9. new Resources

public class Resources {....../*package*/ final AssetManager mAssets;......public Resources(AssetManager assets, DisplayMetrics metrics,Configuration config, CompatibilityInfo compInfo) {mAssets = assets;......updateConfiguration(config, metrics);assets.ensureStringBlocks();}...... }? ? ? ? 這個函數定義在文件frameworks/base/core/java/android/content/res/Resources.java中。

? ? ? ??Resources類的構造函數首先將參數assets所指向的一個AssetManager對象保存在成員變量mAssets中,以便以后可以通過它來訪問應用程序的資源,接下來調用另外一個成員函數updateConfiguration來設置設備配置信息,最后調用參數assets所指向的一個AssetManager對象的成員函數ensureStringBlocks來創建字符串資源池。

? ? ? ? 接下來,我們就首先分析Resources類的成員函數updateConfiguration的實現,接著再分析AssetManager類的成員函數ensureStringBlocks的實現。

? ? ? ? Step 10.?Resources.updateConfiguration

public class Resources {......private final Configuration mConfiguration = new Configuration();......public void updateConfiguration(Configuration config,DisplayMetrics metrics) {synchronized (mTmpValue) {int configChanges = 0xfffffff;if (config != null) {configChanges = mConfiguration.updateFrom(config);}if (mConfiguration.locale == null) {mConfiguration.locale = Locale.getDefault();}if (metrics != null) {mMetrics.setTo(metrics);mMetrics.updateMetrics(mCompatibilityInfo,mConfiguration.orientation, mConfiguration.screenLayout);}mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;String locale = null;if (mConfiguration.locale != null) {locale = mConfiguration.locale.getLanguage();if (mConfiguration.locale.getCountry() != null) {locale += "-" + mConfiguration.locale.getCountry();}}int width, height;if (mMetrics.widthPixels >= mMetrics.heightPixels) {width = mMetrics.widthPixels;height = mMetrics.heightPixels;} else {//noinspection SuspiciousNameCombinationwidth = mMetrics.heightPixels;//noinspection SuspiciousNameCombinationheight = mMetrics.widthPixels;}int keyboardHidden = mConfiguration.keyboardHidden;if (keyboardHidden == Configuration.KEYBOARDHIDDEN_NO&& mConfiguration.hardKeyboardHidden== Configuration.HARDKEYBOARDHIDDEN_YES) {keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;}mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,locale, mConfiguration.orientation,mConfiguration.touchscreen,(int)(mMetrics.density*160), mConfiguration.keyboard,keyboardHidden, mConfiguration.navigation, width, height,mConfiguration.screenLayout, mConfiguration.uiMode, sSdkVersion);......}...... }...... }? ? ? ? 這個函數定義在文件frameworks/base/core/java/android/content/res/Resources.java中。

? ? ? ??Resources類的成員變量mConfiguration指向的是一個Configuration對象,用來描述設備當前的配置信息,這些配置信息對應的就是在前面Android資源管理框架(Asset Manager)簡要介紹和學習計劃一文中提到18個資源維度。

? ? ? ??Resources類的成員函數updateConfiguration首先是根據參數config和metrics來更新設備的當前配置信息,例如,屏幕大小和密碼、國家地區和語言、鍵盤配置情況等等,接著再調用成員變量mAssets所指向的一個Java層的AssetManager對象的成員函數setConfiguration來將這些配置信息設置到與之關聯的C++層的AssetManager對象中去。

? ? ? ? 接下來,我們就繼續分析AssetManager類的成員函數setConfiguration的實現,以便可以了解設備配置信息的設置過程。

? ? ? ? Step 11.?AssetManager.setConfiguration

public final class AssetManager {....../*** Change the configuation used when retrieving resources. Not for use by* applications.* {@hide}*/public native final void setConfiguration(int mcc, int mnc, String locale,int orientation, int touchscreen, int density, int keyboard,int keyboardHidden, int navigation, int screenWidth, int screenHeight,int screenLayout, int uiMode, int majorVersion);...... }? ? ? ? 這個函數定義在文件frameworks/base/core/java/android/content/res/AssetManager.java中。

? ? ? ??AssetManager類的成員函數setConfiguration是一個JNI方法,它是由C++層的函數android_content_AssetManager_setConfiguration來實現的,如下所示:

static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,jint mcc, jint mnc,jstring locale, jint orientation,jint touchscreen, jint density,jint keyboard, jint keyboardHidden,jint navigation,jint screenWidth, jint screenHeight,jint screenLayout, jint uiMode,jint sdkVersion) {AssetManager* am = assetManagerForJavaObject(env, clazz);if (am == NULL) {return;}ResTable_config config;memset(&config, 0, sizeof(config));const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;config.mcc = (uint16_t)mcc;config.mnc = (uint16_t)mnc;config.orientation = (uint8_t)orientation;config.touchscreen = (uint8_t)touchscreen;config.density = (uint16_t)density;config.keyboard = (uint8_t)keyboard;config.inputFlags = (uint8_t)keyboardHidden;config.navigation = (uint8_t)navigation;config.screenWidth = (uint16_t)screenWidth;config.screenHeight = (uint16_t)screenHeight;config.screenLayout = (uint8_t)screenLayout;config.uiMode = (uint8_t)uiMode;config.sdkVersion = (uint16_t)sdkVersion;config.minorVersion = 0;am->setConfiguration(config, locale8);if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8); }? ? ? ? 這個函數定義在文件frameworks/base/core/jni/android_util_AssetManager.cpp中。

? ? ? ? 參數clazz指向的是一個Java層的AssetManager對象,函數android_content_AssetManager_setConfiguration首先調用另外一個函數assetManagerForJavaObject將它的成員變量mObject轉換為一個C++層的AssetManager對象。

? ? ? ? 函數android_content_AssetManager_setConfiguration接下來再根據其它參數來創建一個ResTable_config對象,這個ResTable_config對象就用來描述設備的當前配置信息。

? ? ? ? 函數android_content_AssetManager_setConfiguration最后調用前面獲得C++層的AssetManager對象的成員函數setConfiguration來將前面創建的ResTable_config對象設置到它內部去,以便C++層的AssetManager對象可以根據設備的當前配置信息來找到最合適的資源。

? ? ? ? Step 12.?AssetManager.setConfiguration

void AssetManager::setConfiguration(const ResTable_config& config, const char* locale) {AutoMutex _l(mLock);*mConfig = config;if (locale) {setLocaleLocked(locale);} else if (config.language[0] != 0) {char spec[9];spec[0] = config.language[0];spec[1] = config.language[1];if (config.country[0] != 0) {spec[2] = '_';spec[3] = config.country[0];spec[4] = config.country[1];spec[5] = 0;} else {spec[3] = 0;}setLocaleLocked(spec);} else {updateResourceParamsLocked();} }? ? ? ? 這個函數定義在文件frameworks/base/libs/utils/AssetManager.cpp中。

? ? ? ? AssetManager類的成員變量mConfig指向的是一個ResTable_config對象,用來描述設備的當前配置信息,AssetManager類的成員函數setConfiguration首先將參數config所描述的設備配置信息拷貝到它里面去。

? ? ? ? 如果參數local的值不等于NULL,那么它指向的字符串就是用來描述設備的國家、地區和語言信息的,這時候AssetManager類的成員函數setConfiguration就會調用另外一個成員函數setLocalLocked來將它們設置到AssetManager類的另外一個成員變量mLocale中去。

? ? ? ? 如果參數local的值等于NULL,并且參數config指向的一個ResTable_config對象包含了設備的國家、地區和語言信息,那么AssetManager類的成員函數setConfiguration同樣會調用另外一個成員函數setLocalLocked來將它們設置到AssetManager類的另外一個成員變量mLocale中去。

? ? ? ? 如果參數local的值等于NULL,并且參數config指向的一個ResTable_config對象沒有包含設備的國家、地區和語言信息,那么就說明設備的國家、地區和語言等信息不需要更新,這時候AssetManager類的成員函數setConfiguration就會直接調用另外一個成員函數updateResourceParamsLocked來更新資源表中的設備配置信息。

? ? ? ? 注意,AssetManager類的成員函數setLocalLocked來更新了成員變量mLocale的內容之后,同樣會調用另外一個成員函數updateResourceParamsLocked來更新資源表中的設備配置信息。

? ? ? ??AssetManager類的成員函數updateResourceParamsLocked的實現如下所示:

void AssetManager::updateResourceParamsLocked() const {ResTable* res = mResources;if (!res) {return;}size_t llen = mLocale ? strlen(mLocale) : 0;mConfig->language[0] = 0;mConfig->language[1] = 0;mConfig->country[0] = 0;mConfig->country[1] = 0;if (llen >= 2) {mConfig->language[0] = mLocale[0];mConfig->language[1] = mLocale[1];}if (llen >= 5) {mConfig->country[0] = mLocale[3];mConfig->country[1] = mLocale[4];}mConfig->size = sizeof(*mConfig);res->setParameters(mConfig); }? ? ? ??這個函數定義在文件frameworks/base/libs/utils/AssetManager.cpp中。

? ? ? ??AssetManager類的成員變量mResources指向的是一個ResTable對象,這個ResTable對象描述的就是一個資源索引表。Android應用程序的資源索引表的格式以及生成過程可以參考前面Android應用程序資源的編譯和打包過程分析一文。

? ? ? ??AssetManager類的成員函數updateResourceParamsLocked首先是將成員變量mLocale所描述的國家、地區和語言信息更新到另外一個成員變量mConfig中去,接著再將成員變量mConfig所包含的設備配置信息設置到成員變量mResources所描述的一個資源索引表中去,這是通過調用成員變量mResources所指向的一個ResTable對象的成員函數setParameters來實現的。

? ? ? ? 這一步執行完成之后,返回到前面的Step 9中,即Resources類的構造函數,接下來它就會調用AssetManager類的成員函數ensureStringBlocks來創建字符串資源池。

? ? ? ? Step 13.?AssetManager.ensureStringBlocks

public final class AssetManager {......private StringBlock mStringBlocks[] = null;....../*package*/ final void ensureStringBlocks() {if (mStringBlocks == null) {synchronized (this) {if (mStringBlocks == null) {makeStringBlocks(true);}}}}...... }? ? ? ? 這個函數定義在文件frameworks/base/core/java/android/content/res/AssetManager.java中。

? ? ? ??AssetManager類的成員變量mStringBlocks指向的是一個StringBlock數組,其中,每一個StringBlock對象都是用來描述一個字符串資源池。從前面Android應用程序資源的編譯和打包過程分析一文可以知道,每一個資源表都包含有一個資源項值字符串資源池,AssetManager類的成員變量mStringBlocks就是用來保存所有的資源表中的資源項值字符串資源池的。

? ? ? ??AssetManager類的成員函數ensureStringBlocks首先檢查成員變量mStringBlocks的值是否等于null。如果等于null的話,那么就說明當前應用程序使用的資源表中的資源項值字符串資源池還沒有讀取出來,這時候就會調用另外一個成員函數makeStringBlocks來進行讀取。

? ? ? ?Step 14.?AssetManager.makeStringBlocks

public final class AssetManager {......private final void makeStringBlocks(boolean copyFromSystem) {final int sysNum = copyFromSystem ? sSystem.mStringBlocks.length : 0;final int num = getStringBlockCount();mStringBlocks = new StringBlock[num];......for (int i=0; i<num; i++) {if (i < sysNum) {mStringBlocks[i] = sSystem.mStringBlocks[i];} else {mStringBlocks[i] = new StringBlock(getNativeStringBlock(i), true);}}}......private native final int getStringBlockCount();private native final int getNativeStringBlock(int block);...... }

? ? ? ??這個函數定義在文件frameworks/base/core/java/android/content/res/AssetManager.java中。

? ? ? ? 參數copyFromSystem表示是否要將系統資源表里面的資源項值字符串資源池也一起拷貝到成員變量mStringBlokcs所描述的一個數組中去。如果它的值等于true的時候,那么AssetManager就會首先獲得makeStringBlocks首先獲得系統資源表的個數sysNum,接著再獲得總的資源表個數num,這是通過調用JNI方法getStringBlockCount來實現的。注意,總的資源表個數num是包含了系統資源表的個數sysNum的。

? ? ? ? 從前面的Step 4可以知道,用來訪問系統資源包的AssetManager對象就保存在AssetManager類的靜態成員變量sSystem中,并且這個AssetManager對象是最先被創建以及初始化的。也就是說,當執行到這一步的時候,所有系統資源表的資源項值字符串資源池已經讀取出來,它們就保存在AssetManager類的靜態成員變量sSystem所描述的一個AssetManager對象的成員變量mStringBlocks中,因此,只將它們拷貝到當前正在處理的AssetManager對象的成員變量mStringBlokcs的前sysNum個位置上去就可以了。

? ? ? ? 最后,AssetManager類的成員函數makeStringBlocks就調用另外一個JNI方法getNativeStringBlock來讀取剩余的其它資源表的資源項值字符串資源池,并且分別將它們封裝在一個StringBlock對象保存在成員變量mStringBlokcs所描述的一個數組中。

? ? ? ??AssetManager類的JNI方法getNativeStringBlock實際上就是將每一個資源包里面的resources.arsc文件的資源項值字符串資源池數據塊讀取出來,并且封裝在一個C++層的StringPool對象中,然后AssetManager類的成員函數makeStringBlocks再將該StringPool對象封裝成一個Java層的StringBlock中。關于資源表中的資源項值字符串資源池的更多信息,可以參考前面Android應用程序資源的編譯和打包過程分析一文。

? ? ? ? 至此,我們就分析完成Android應用程序資源管理器的創建的初始化過程了,主要就是創建和初始化用來訪問應用程序資源的AssetManager對象和Resources對象,其中,初始化操作包括設置AssetManager對象的資源文件路徑以及設備配置信息等。有了這兩個初始化的AssetManager對象和Resources對象之后,在接下來的一篇文章中,我們就可以繼續分析應用程序資源的查找過程了,敬請關注!

老羅的新浪微博:http://weibo.com/shengyangluo,歡迎關注!

轉載于:https://www.cnblogs.com/wuyida/archive/2013/04/22/6300513.html

總結

以上是生活随笔為你收集整理的Android应用程序资源管理器(Asset Manager)的创建过程分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

久久久久欠精品国产毛片国产毛生 | 国产在线不卡精品 | 91亚洲精品国偷拍自产在线观看 | 久久黄色免费观看 | 97视频在线观看播放 | 久久久国产一区二区三区 | 一区二区av | 日韩一级成人av | 国产色在线视频 | 婷婷精品国产欧美精品亚洲人人爽 | 欧美成人精品在线 | 激情久久久 | 人交video另类hd | 久久在视频| 91精品啪| 人人搞人人爽 | 免费网站v | 999久久精品| 久久不卡电影 | 久久久久久久免费看 | 久久成视频| 国产流白浆高潮在线观看 | 国产精品入口66mio女同 | 亚洲综合色婷婷 | 日韩欧美一区二区三区视频 | 国产91精品一区二区麻豆网站 | 91九色在线视频观看 | 中文字幕国产 | 免费看搞黄视频网站 | 91视频啊啊啊 | av大片网址 | 久久综合网色—综合色88 | 国产一区二区三区网站 | 99久久久成人国产精品 | 五月天综合激情 | 九色91av| 亚洲免费在线看 | 成人在线视频你懂的 | 丝袜美腿亚洲综合 | 国产成人免费在线观看 | 天天舔天天搞 | 日韩欧美99 | 日韩欧美在线第一页 | 91精品国自产在线偷拍蜜桃 | 日日夜夜骑 | 国产亚洲精品电影 | 国产美女被啪进深处喷白浆视频 | 五月色婷 | 在线免费国产 | 一级黄色大片在线观看 | 久久热亚洲 | 97av在线视频免费播放 | 国产成人一区二区三区在线观看 | 91在线中文字幕 | 搡bbbb搡bbb视频 | 久久久久北条麻妃免费看 | 日韩中文字幕免费视频 | 狠狠干成人综合网 | 欧美 国产 视频 | 黄色免费观看视频 | 成年美女黄网站色大片免费看 | 国产亚洲日本 | 亚洲精品av中文字幕在线在线 | 天天操天天射天天舔 | 97视频免费观看 | 国产精品精品国产 | 久久视频这里有精品 | 玖玖综合网 | 狠狠干狠狠艹 | 国产在线精品一区二区不卡了 | 一区二区三区精品在线 | 亚洲a在线观看 | 国内偷拍精品视频 | 超级碰视频 | 五月天最新网址 | 国产在线看一区 | 日韩在线播放视频 | 国产不卡在线看 | 成年人在线观看视频免费 | 国产一级淫片免费看 | 免费看日韩 | 精品国产美女在线 | 在线观看免费高清视频大全追剧 | 97电影网手机版 | 亚洲一片黄 | 成人av电影在线观看 | 又黄又爽又湿又无遮挡的在线视频 | 亚洲精品久久久蜜桃直播 | 久久99精品国产99久久 | 精品亚洲视频在线观看 | 久久久黄色av | 色综合 久久精品 | 五月婷婷开心中文字幕 | 4438全国亚洲精品在线观看视频 | 亚洲激情电影在线 | 在线观影网站 | 日韩视频免费在线观看 | 亚洲精品色 | 国产成人精品女人久久久 | 91av视频导航 | 黄污网 | 一级大片在线观看 | 欧美精品一区在线发布 | 久久成人高清 | 日韩首页 | 欧美成年网站 | 福利视频区 | 国产精品区一区 | 91在线在线观看 | 伊人黄色网 | 在线看片日韩 | 久久久久国产精品午夜一区 | 综合激情网 | 五月天色站 | 久久久久国产精品免费免费搜索 | 天天干夜夜操视频 | 久久69av | 色在线免费视频 | 伊人网综合在线观看 | 又爽又黄在线观看 | 精品一区 在线 | 美女黄频在线观看 | 在线观看网站你懂的 | 97色婷婷 | 久久午夜网 | 在线免费观看视频一区二区三区 | 亚洲国产播放 | 久久成人亚洲欧美电影 | 九九热在线免费观看 | 亚洲精品国产自产拍在线观看 | www.av中文字幕.com | 99久久久国产精品免费99 | 国产亚洲精品bv在线观看 | 99久热在线精品 | 亚州精品在线视频 | 国产 成人 久久 | 亚洲一二三区精品 | 久久久一本精品99久久精品66 | 波多野结衣电影一区二区 | 免费av在线网站 | 97人人模人人爽人人喊网 | 人人澡人人爽欧一区 | 久久伦理电影网 | 亚洲成av片人久久久 | 韩国精品一区二区三区六区色诱 | 伊人干综合 | 91麻豆精品国产自产 | 男女啪啪免费网站 | 亚洲精品国产成人 | 久久精品免费电影 | 国产一区 在线播放 | 99这里只有精品视频 | 亚洲aⅴ久久精品 | 综合久久久久久久 | 在线日韩av | 日韩欧美专区 | 国产专区欧美专区 | 黄色福利| 丝袜美腿亚洲 | 日韩av在线一区二区 | www.狠狠操| 中文在线8资源库 | 色噜噜狠狠色综合中国 | 一级性视频 | 精品在线你懂的 | 91理论片午午伦夜理片久久 | 91成人午夜| 欧美va天堂在线电影 | 五月婷久 | 射久久| 丁香花中文在线免费观看 | av在线播放免费 | 国产无套精品久久久久久 | 天天爽人人爽夜夜爽 | 色99视频 | 午夜精品一区二区三区在线观看 | 日韩欧美在线免费观看 | 国产精品久久久久久久久久久久午夜 | 最近最新中文字幕 | 一区二区视频欧美 | 亚洲天天在线 | 精品久操| 最新国产一区二区三区 | 中文字幕中文字幕 | 欧美另类一二三四区 | 中文字幕在线观看国产 | 免费看一及片 | 99久久久成人国产精品 | 精品在线视频一区二区三区 | 久av在线 | 在线观看的av网站 | 免费特级黄色片 | 久久久黄色免费网站 | 91九色蝌蚪视频 | 成人欧美亚洲 | 91精品视频在线观看免费 | 国产免费叼嘿网站免费 | 欧美另类sm图片 | 曰韩在线| 成人欧美一区二区三区在线观看 | 欧美日韩国产一二三区 | 久久国产精品区 | 91日韩精品视频 | 女人18片 | 99精品色 | 久久国产影视 | 久久国产乱 | 精品一区二区精品 | 免费看一级特黄a大片 | 伊人宗合网 | 免费在线观看一区二区三区 | 波多野结衣视频一区二区三区 | 在线观看中文字幕一区二区 | 91精品久久久久久久91蜜桃 | 中文字幕在线观看视频网站 | 亚洲国内精品 | 国产裸体bbb视频 | 日韩精品最新在线观看 | 国产精品一级在线 | www.狠狠色 | 麻豆视频免费网站 | 国产精品美女999 | 日韩专区一区二区 | 免费在线观看视频一区 | 久久精品视频免费播放 | 欧美日韩视频免费 | 丁香花中文在线免费观看 | 色99在线| 亚洲精品欧洲精品 | 91成人破解版 | 人人爱天天操 | av在线免费在线 | 日韩a免费 | 免费在线观看不卡av | 九九九视频精品 | 国产高清视频在线 | 一区二区三区在线免费 | www.五月天婷婷 | jizz欧美性9| av成人免费在线观看 | 九九三级毛片 | 久久国产电影院 | 91av视频免费观看 | 一区二区三区av在线 | 久久久免费少妇 | 性色va | 午夜私人影院 | 国产亚洲精品久久 | 人人涩 | 成人黄色在线 | 欧美怡红院 | 粉嫩av一区二区三区四区五区 | 亚洲欧美激情插 | 亚洲视频观看 | 97在线视频观看 | 精品久久久久久久久久久院品网 | 中文字幕在线观看完整版 | 亚洲中字幕 | 色九九在线 | 国产精品成人国产乱 | 精品一区二区综合 | 三级av小说 | 亚洲精品美女久久久 | 国精产品999国精产 久久久久 | 天天色婷婷 | 一本一本久久a久久精品牛牛影视 | 久久综合久久综合九色 | 视频一区在线免费观看 | 91丨九色丨国产女 | 97超碰人人澡人人 | 五月婷婷中文网 | 国产三级香港三韩国三级 | 成人毛片久久 | 在线观看日韩国产 | 91热视频在线观看 | 婷婷久久婷婷 | 国产日韩精品在线 | 国产黄色免费 | 午夜私人影院久久久久 | 日韩精品欧美视频 | av噜噜噜在线播放 | 国产精品白浆 | 国产在线国偷精品产拍免费yy | 久久精品免视看 | 亚洲天堂香蕉 | 国产麻豆剧传媒免费观看 | 97人人精品 | 在线观看国产 | 国产精品久久一区二区三区, | 国产精品久久久久久久免费观看 | 黄色aa久久| 国产精品免费一区二区 | 成人毛片一区 | 91亚洲精品久久久 | 国产精品麻豆果冻传媒在线播放 | 久久中文字幕在线视频 | 色婷婷综合久色 | 国产福利精品在线观看 | 免费久久久久久 | www.婷婷com| a视频免费看 | 国产精品久久久久久久久久久久午 | 午夜电影 电影 | 九九九热精品免费视频观看 | 国产黄影院色大全免费 | 国产精品不卡av | 国产成人精品一区二区三区 | 国产 中文 日韩 欧美 | 黄色片网站大全 | 91亚洲网站| 国产精品视频免费 | 国产不卡在线视频 | 日本中文字幕在线免费观看 | 99re国产视频 | 日本久久久久久久久久 | 色婷婷亚洲婷婷 | 五月婷婷开心 | 久久久久免费精品国产 | 一区二区三区播放 | 亚洲美女精品视频 | 青青河边草免费观看 | 91久久久国产精品 | 日韩高清成人 | 少妇bbbb搡bbbb搡bbbb | 亚洲综合欧美日韩狠狠色 | av在线最新 | 黄色电影小说 | 国产涩涩网站 | 婷婷激情av| 国产精品视屏 | 久久草| 日韩伦理一区二区三区av在线 | 视频国产精品 | 久久96国产精品久久99软件 | 中文字幕亚洲不卡 | 亚洲天天干 | 免费av免费观看 | 国产.精品.日韩.另类.中文.在线.播放 | 日韩久久久久久 | 91精品办公室少妇高潮对白 | 亚洲精品日韩av | 波多野结衣视频一区二区 | 天天干天天草天天爽 | 少妇bbbb| 婷婷丁香国产 | 国产亚洲精品女人久久久久久 | 久久精品一区 | 日韩av在线影视 | 亚洲精品91天天久久人人 | 欧美成人在线网站 | 中文字幕一区二区三区四区在线视频 | 999久久久免费视频 午夜国产在线观看 | 91亚洲精品乱码久久久久久蜜桃 | 久久在线观看视频 | 99精品免费网 | 97超碰资源站 | 免费视频区 | 国产视 | 国产69久久 | 日韩av免费大片 | 久久精品精品 | 久久精彩 | 亚洲欧美国产日韩在线观看 | 91精品播放 | 亚洲成人av片 | 成人一级视频在线观看 | av在线网站观看 | 色99中文字幕| 蜜桃视频精品 | 99在线免费视频 | 免费a网| 日韩专区中文字幕 | 91视频在线国产 | 国产在线色 | 婷婷电影在线观看 | 免费在线激情视频 | av观看免费在线 | 日本婷婷色 | 欧美一二区视频 | 99久久999久久久精玫瑰 | 亚洲综合在线视频 | 超级碰碰免费视频 | 国产区 在线 | 国产精品一区二区电影 | 国内精品小视频 | 久久国产精品久久久 | 欧美最新另类人妖 | 国产免费激情久久 | av日韩精品 | 国产成人精品女人久久久 | 色资源网免费观看视频 | 在线电影 一区 | 午夜视频福利 | 久久久国产精华液 | 欧美少妇18p | 久久99热久久99精品 | 日批视频在线观看免费 | 免费一级片久久 | 99久久婷婷国产 | 亚洲一级二级三级 | 久久怡红院 | av黄色影院 | 日韩二区三区在线 | 麻豆成人在线观看 | 免费日韩一区二区三区 | 奇米影视777四色米奇影院 | 狠狠五月天 | 亚洲免费婷婷 | 99se视频在线观看 | 91福利影院在线观看 | 91秒拍国产福利一区 | 激情网在线视频 | 天堂av免费在线 | 伊人亚洲综合网 | 日韩高清在线一区二区三区 | av在线免费在线观看 | 国产精品丝袜 | 精品国产_亚洲人成在线 | 天天添夜夜操 | 永久免费看av | 中文字幕av全部资源www中文字幕在线观看 | 日韩一区正在播放 | 麻豆影视在线免费观看 | 激情六月婷婷久久 | 欧美 亚洲 另类 激情 另类 | 福利一区在线视频 | 亚洲色五月 | 亚洲第一色 | 92国产精品久久久久首页 | 在线播放 日韩专区 | 亚洲欧美日韩一区二区三区在线观看 | 国产视频精品免费 | 久久精精品视频 | 在线看成人av | 久久精品视频在线免费观看 | 蜜臀久久99精品久久久久久网站 | 天天综合狠狠精品 | 91在线视频一区 | 午夜国产福利在线 | 在线超碰av | 久草在线最新免费 | 亚洲片在线资源 | 四虎影视成人永久免费观看亚洲欧美 | 国产精品剧情 | 国产91精品高清一区二区三区 | 九九视频精品免费 | 日韩中文在线播放 | 亚洲最新精品 | 亚洲少妇xxxx| 欧美成年黄网站色视频 | 超碰在线观看av.com | 永久免费毛片在线观看 | 精品亚洲va在线va天堂资源站 | 欧美日韩精品综合 | 激情五月综合 | wwwwww国产 | 一级黄色免费网站 | 99热国产在线观看 | 天天综合网天天综合色 | www日韩精品 | 97视频资源| 成人免费看片网址 | 天天色天天射天天干 | 男女激情麻豆 | 国产九九热视频 | 成人在线电影观看 | 在线免费黄网站 | 亚洲日b视频 | 中文字幕成人 | 中午字幕在线观看 | 久久精品福利 | 欧美性色黄 | 欧美精品v国产精品v日韩精品 | 成人在线视频论坛 | 久久福利| 国产精品久久久毛片 | 丁香婷婷激情啪啪 | 免费三级骚 | 日韩午夜精品 | 激情五月播播久久久精品 | 天天综合天天做 | 日韩中文字幕国产精品 | 亚洲桃花综合 | 成人永久视频 | 久久er99热精品一区二区三区 | 欧美网站黄色 | 国产亚洲精品久久久久久电影 | 91网页版在线观看 | 国产黄视频在线观看 | 99国产精品免费网站 | 天天色婷婷 | 一级黄色片在线免费看 | 欧美精品亚州精品 | 久久免费国产精品 | 欧美一性一交一乱 | 中文字幕一区二区三区四区久久 | 国产99久久久欧美黑人 | 天天操天天谢 | 久草新在线 | 久久久久久国产精品免费 | 久久久久久欧美二区电影网 | 麻豆系列在线观看 | 欧美日本高清视频 | 狠狠色丁香婷婷综合视频 | 美女视频久久久 | 国产精品一区二区免费 | 精品播放 | 色综合久久久久综合体 | av免费网 | 夜夜操天天摸 | 激情视频91 | 中中文字幕av在线 | 国产人免费人成免费视频 | 波多野结衣精品在线 | 黄色免费网 | 国产亚洲婷婷 | 亚洲天堂网在线播放 | 91成人在线观看高潮 | 97人人澡人人添人人爽超碰 | 成年人免费看的视频 | 免费视频黄色 | 亚洲综合精品视频 | 91mv.cool在线观看 | 久久精品国产一区 | 97在线视频免费看 | 色爽网站 | av一级片网站 | 国产香蕉久久 | 欧美日韩在线视频一区二区 | 日本黄色免费在线观看 | 人人干免费 | 激情综合色综合久久 | 亚洲在线不卡 | 婷婷免费在线视频 | 久久久久亚洲精品 | 一区二区丝袜 | 网站在线观看日韩 | 91视频这里只有精品 | a天堂在线看 | 激情图片区 | 国产精品99久久久久久人免费 | 黄污视频网站大全 | 久久99热精品这里久久精品 | 国产69精品久久久久9999apgf | 久久国产亚洲视频 | 国产精品美女久久久久久久久久久 | 草久中文字幕 | 色资源二区在线视频 | 亚洲精品国产精品国自产观看 | 国产精品午夜在线观看 | 亚洲最大的av网站 | 欧美在线日韩在线 | 色窝资源 | 成年人免费av | 99综合视频 | 日韩免费小视频 | 亚洲精品视频播放 | 亚洲精选视频在线 | 97人人模人人爽人人喊中文字 | 亚洲精品视 | 国产一二三四在线视频 | 91天天操 | 奇米网8888 | 亚洲国产精品久久久久 | 欧美一区三区四区 | 日韩久久精品一区二区三区 | 中文字幕中文 | 国产精品久久久久一区 | 欧美色图亚洲图片 | 欧美日韩高清一区二区 国产亚洲免费看 | 成人a级免费视频 | 色婷婷av一区二 | 97超碰资源网 | 免费网站黄色 | 黄色av免费 | 麻豆国产视频下载 | 九色自拍视频 | 公与妇乱理三级xxx 在线观看视频在线观看 | 欧美福利视频一区 | 美女免费视频网站 | 九九热久久免费视频 | 黄色av电影在线观看 | 日韩欧美一区二区三区视频 | 一二三区av | 狠狠色综合网站久久久久久久 | 狠狠色综合欧美激情 | 国产精品欧美一区二区三区不卡 | 久草久草久草久草 | 婷婷国产在线 | 亚洲人成精品久久久久 | 日韩免费小视频 | 黄网在线免费观看 | 九色91视频 | 久久久久久久久久久综合 | 在线v片免费观看视频 | 又爽又黄在线观看 | 久久精品国产一区二区三区 | 久久综合欧美精品亚洲一区 | 天天天干天天天操 | 免费亚洲成人 | 亚洲精品白浆高清久久久久久 | 在线亚州| 五月花激情 | 久久免费毛片视频 | 国产黄色片免费观看 | 黄色国产大片 | 久久精品99国产精品亚洲最刺激 | 在线色亚洲| 91看片麻豆 | 91麻豆精品 | 黄色影院在线观看 | 久久在线视频精品 | 天天爽天天爽 | 91探花国产综合在线精品 | 精品视频久久久 | 日日摸日日添夜夜爽97 | 最近中文字幕高清字幕在线视频 | 国产韩国日本高清视频 | 成人欧美日韩国产 | 亚洲网站在线看 | 天天操天天操天天操天天 | 亚洲视频免费 | 又色又爽的网站 | 激情综合电影网 | 免费h精品视频在线播放 | 成人在线播放免费观看 | 丝袜av一区 | 麻豆视频在线免费观看 | 九九在线播放 | 天天搞天天干天天色 | 成人在线免费小视频 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 欧美日韩国产精品一区二区 | 99色视频在线 | 在线观看日本高清mv视频 | 亚洲激情婷婷 | 国产又黄又爽无遮挡 | www.国产毛片 | 久草精品在线播放 | 国产精品一区二区在线观看免费 | 国产艹b视频 | 久久综合亚洲鲁鲁五月久久 | 蜜桃久久久 | 国产精品一区二区免费 | 欧美在线日韩在线 | 97超碰人人澡人人 | 国产成人精品午夜在线播放 | 国产一区自拍视频 | 日产乱码一二三区别免费 | 免费观看www7722午夜电影 | 国产视频在线免费观看 | 国产精品69av | 久久久综合色 | 中文在线字幕免费观看 | 黄网站大全 | 日韩大片在线免费观看 | 久久成人精品视频 | 国产精品久久久久久久久久久久 | www.com.黄| 欧美色一色 | 在线观看你懂的网址 | 五月激情站 | 国产精品视频免费观看 | 麻豆精品视频在线观看免费 | 又粗又长又大又爽又黄少妇毛片 | 超碰人人射 | www.天天草| 亚洲午夜精品电影 | 免费在线观看成人av | 亚洲一级黄色片 | 久久久久网址 | 国产精品24小时在线观看 | 最新日本中文字幕 | 中文字幕国语官网在线视频 | 久久国产三级 | 中文字幕视频在线播放 | 337p日本大胆噜噜噜噜 | 国产在线观看污片 | 亚洲视频在线观看网站 | 最新不卡av| 不卡av在线 | 国产在线资源 | 婷婷伊人五月 | 99精品视频99| 91成人精品一区在线播放69 | 成人av免费播放 | 免费又黄又爽的视频 | 久久精品爱视频 | 亚洲一区二区三区毛片 | 久要激情网 | 黄色成年片 | 人人超在线公开视频 | 热久久电影 | 国产高清在线免费 | 国产精品三级视频 | 日韩视频一区二区在线 | 精品在线二区 | 在线亚洲午夜片av大片 | 人人藻人人澡人人爽 | 久久久久女教师免费一区 | 国产视频手机在线 | 中文字幕在线看视频国产中文版 | 日日夜夜av | 亚洲激情综合 | 亚洲激情视频 | 国产精品久久久久久久久毛片 | 日韩专区在线 | 黄色电影小说 | av网在线观看 | 日韩欧美在线综合网 | 午夜三级福利 | 91桃色免费视频 | 日韩精品久久一区二区 | 丁香5月婷婷久久 | 天无日天天操天天干 | 亚洲国产一区二区精品专区 | 久久er99热精品一区二区三区 | 国产精品美女久久久久久久网站 | 亚洲精品国精品久久99热 | 丁香婷婷在线 | 国产高清精 | 69精品久久久| 免费在线观看污网站 | 看国产黄色片 | 久久国产精品成人免费浪潮 | 97精品电影院 | adn—256中文在线观看 | 久久久久久久免费观看 | 黄色av一区二区 | 精品国产乱码久久久久久天美 | 成人毛片100免费观看 | 精产嫩模国品一二三区 | 久久不射电影网 | 国产综合精品久久 | 日日夜夜人人精品 | 97精品在线视频 | 国产一区在线视频观看 | 国产精品美女久久久久久 | 亚洲日本va午夜在线电影 | 手机在线看a | 国产午夜精品av一区二区 | 97电影在线观看 | 三级av在线免费观看 | 亚洲一区二区三区在线看 | 天天操天天射天天爱 | 久久久夜色 | 日韩av男人的天堂 | 96看片 | 国产一区二区三区免费在线观看 | 激情小说久久 | 天天操天天爱天天爽 | 毛片网站免费在线观看 | 亚州国产视频 | 国产福利不卡视频 | 在线观看av不卡 | 亚洲黄色免费在线看 | a在线v| 天天插狠狠插 | 国产精品美女久久久久久久 | 日韩中文字幕a | 亚洲成人av电影在线 | 五月婷婷激情网 | 在线观看成人 | 久久精品香蕉 | 亚洲少妇久久 | 日韩乱码在线 | 亚洲综合色丁香婷婷六月图片 | 亚洲精品高清一区二区三区四区 | 日韩国产欧美在线视频 | 99久久影视 | av成人免费在线观看 | av字幕在线 | 一二三区视频在线 | 国产盗摄精品一区二区 | 日韩区在线观看 | 国产精品一区二区av日韩在线 | 亚洲精品免费在线观看视频 | 超级碰视频 | 久久精品—区二区三区 | 一级α片免费看 | 国产精品刺激对白麻豆99 | 精品福利片 | 九九在线视频免费观看 | 91av社区| 国产中文字幕在线免费观看 | 青青草久草在线 | 精品专区 | 成人高清在线 | 精品久久免费 | 婷婷色综| 欧美激情第28页 | 成人播放器 | 成片免费观看视频999 | 国产乱码精品一区二区三区介绍 | 色九九影院 | 日韩欧美视频在线免费观看 | 国产一区播放 | 五月婷婷激情综合网 | 国产精品手机播放 | 国产精品一区二区视频 | 深夜免费福利在线 | 久久久久国产精品一区 | 91在线影院| 天天射天天干天天 | 东方av在线免费观看 | www..com毛片| 激情久久综合 | 99激情网 | 免费能看的黄色片 | 久久电影中文字幕视频 | 91激情视频在线播放 | 黄色免费在线视频 | 97色婷婷成人综合在线观看 | 国产精品99久久久精品 | 欧美巨大荫蒂茸毛毛人妖 | 亚洲干视频在线观看 | 色婷婷久久 | 久久久久婷| 在线韩国电影免费观影完整版 | 在线观看涩涩 | 在线 视频 一区二区 | 免费精品视频在线 | 色婷婷在线观看视频 | 国产精品综合久久久久久 | 五月开心六月伊人色婷婷 | av专区在线 | 一级黄色片在线免费观看 | 国产在线 一区二区三区 | 日韩系列在线观看 | 久久伊人精品一区二区三区 | 91九色性视频 | 福利区在线观看 | 久久亚洲福利 | 国产中文伊人 | 欧美日韩免费在线视频 | 亚洲免费永久精品国产 | 又黄又刺激又爽的视频 | 91久色蝌蚪 | 亚洲少妇自拍 | 一区二区三区四区不卡 | 国产精品女同一区二区三区久久夜 | 欧洲一区二区在线观看 | 99精品国产高清在线观看 | 亚洲一区日韩精品 | 国产精品国产亚洲精品看不卡 | 久草在线观看资源 | 最近中文字幕完整高清 | 在线成人高清电影 | 久久精品网址 | 一区二区三区在线免费播放 | 欧美精品乱码久久久久 | 黄污视频网站大全 | 精品视频免费播放 | 国产传媒中文字幕 | 欧美少妇xxx | 精品免费在线视频 | 五月婷婷丁香网 | a级国产乱理论片在线观看 伊人宗合网 | 精品国产免费看 | 日韩1级片 | 中文字幕在线观看视频一区二区三区 | 奇米网8888| 亚洲免费av一区二区 | 国产久视频 | 91免费版在线 | 中文在线最新版天堂 | 奇人奇案qvod | 亚洲黄色在线观看 | 天天操天天舔天天干 | 伊色综合久久之综合久久 | 日韩精品aaa| 麻豆视频一区二区 | 国产精品网红直播 | 成人一区二区三区在线 | 超碰97免费在线 | 亚洲欧美综合精品久久成人 | 日av免费 | 免费在线色视频 | 在线观看日本高清mv视频 | 黄色com| 久久久久女人精品毛片九一 | 久久午夜免费观看 | 久久精品亚洲一区二区三区观看模式 | 在线播放日韩 | 国偷自产视频一区二区久 | 天天曰夜夜爽 | 九九免费在线观看视频 | 国产成人1区 | 亚洲资源一区 | 久久伦理 | 久草91视频 | 免费在线激情电影 | 亚洲国产午夜视频 | 国产伦精品一区二区三区四区视频 | 在线精品视频在线观看高清 | 日韩精品视频网站 | 久久久久国产精品午夜一区 | 国产精品久久久久久吹潮天美传媒 | 91久久久久久久 | 超碰在线最新 | 欧美日韩亚洲第一页 | 日韩免费在线观看视频 | 99热这里是精品 | 亚洲国产精品va在线 | 手机看片福利 | 国产精品久久久久久久久久不蜜月 | 国产专区精品 | 99热国产在线中文 | 国产99久久久精品 | 永久av免费在线观看 | 在线观看亚洲免费视频 | 久久久国产精品电影 | 在线av资源 | 精品美女久久久久 | 国产精品久久久久久久婷婷 | aaa免费毛片 | 亚洲综合成人婷婷小说 | 成人性生交视频 | 国产免费影院 | 夜添久久精品亚洲国产精品 | 日韩视频一区二区三区在线播放免费观看 | av片一区二区 | 亚洲视频 视频在线 | 亚洲午夜激情网 | 久久成人综合视频 | 一本一本久久a久久精品综合妖精 | 丁香六月伊人 | 精品视频在线免费观看 | 91av视频免费在线观看 | 免费黄色网止 | 日韩大片在线免费观看 | 激情在线网址 | 国产伦理一区二区三区 | 久久国产香蕉视频 | 亚洲午夜久久久综合37日本 | 亚洲国产高清在线观看视频 | 日日摸日日爽 | 在线免费观看国产视频 | 亚洲综合网站在线观看 | av中文字幕不卡 | 美女国产免费 | 天天操天天射天天插 | 丁香色婷 | 四虎成人精品 | 天天婷婷 | 中文字幕在线观看免费高清电影 | 欧美午夜精品久久久久 | 久久理论影院 | 日韩欧美在线第一页 | 顶级bbw搡bbbb搡bbbb | 99久久影视| 日韩在线观看视频网站 | 欧美一级大片在线观看 | 亚洲国产大片 | 欧美日韩精品在线一区二区 | 国产一在线精品一区在线观看 | 探花视频免费观看 | 黄色大片日本免费大片 | 天天躁日日躁狠狠躁 | 看片网站黄色 | 久久综合九色综合欧美就去吻 | 综合久久精品 | 亚洲精品国产综合99久久夜夜嗨 | 国产精品国产三级国产专区53 | av千婊在线免费观看 | 不卡的av | freejavvideo日本免费| aaawww| 精品视频成人 | 九九天堂 | 久久久久久免费视频 | 午夜久久福利 | 女人18片毛片90分钟 | 人人干人人添 | 欧美精品在线一区 | 久久久免费看片 | 日本久久久久久 | 在线精品国产 | 久久久在线 | 91看毛片| 草久久精品 | 免费看国产精品 | 一区二区三区动漫 | 免费观看www视频 | 色综合天天做天天爱 | 九七视频在线观看 | 久久久精品电影 | 久久免费观看视频 | 国产另类av | 国产在线播放一区二区 | 2022久久国产露脸精品国产 | 精品uu| 91成人免费看片 | 国产在线观看免费av | 午夜视频日本 | 黄色a在线观看 | 爱干视频 | 黄av免费|