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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

微信tinker导致冷启动变慢的问题优化

發布時間:2023/12/31 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 微信tinker导致冷启动变慢的问题优化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

微信tinker導致冷啟動變慢的問題優化

  • 1. Android S用戶反饋微信啟動慢
  • 2. 抓取微信systrace查看一下
  • 3. tinker對冷啟動時間的影響
  • 4. 修改方案
  • 5. Open Dex是什么時候觸發的?其中傳入的location又是那里來的?
  • 6. 斷點看一下帶tinker和不帶tinker的ClassLoader
  • 7. 微信內部tinker加載的流程
  • 8. Android S優化tinker導致啟動慢的方案

1. Android S用戶反饋微信啟動慢

首先第一個想到的就是dex的狀態問題

  • 是否有進行oat dex(例如bg dex或者其它類型dex),oat文件和art文件是否正常
  • 是否未保護常用通訊類軟件,用戶感知度強的這類,一般都不建議隨意回收,
  • 老問題是否,存在tinker(微信熱更新,在Google play是禁止這類行為的,一般出現在國內下載的app)
  • 其它情況
  • 2. 抓取微信systrace查看一下

    => 可以看到果然出現了tinker
    OpenDexFilesFromOat(/data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/tinker_classN.apk)

    => 查看一下/data/user/0/com.tencent.mm/tinker/目錄,發現是有很多tinker的內容

    $ adb shell ls -al /data/user/0/com.tencent.mm/tinker/
    drwx------ 3 u0_a211 u0_a211 3452 2021-12-21 16:27 .
    drwx------ 46 u0_a211 u0_a211 3452 2021-12-22 08:56 …
    -rw------- 1 u0_a211 u0_a211 0 2021-12-22 08:57 info.lock
    drwx------ 6 u0_a211 u0_a211 3452 2021-12-21 15:57 patch-66e50d2a
    -rw-rw-rw- 1 u0_a211 u0_a211 359 2021-12-21 16:25 patch.info
    -rw------- 1 u0_a211 u0_a211 42 2021-12-22 08:57 safemode_count_rec_com.tencent.mm
    -rw------- 1 u0_a211 u0_a211 42 2021-12-21 17:32 safemode_count_rec_com.tencent.mm:appbrand0
    -rw------- 1 u0_a211 u0_a211 42 2021-12-22 08:57 safemode_count_rec_com.tencent.mm:appbrand1
    -rw------- 1 u0_a211 u0_a211 42 2021-12-21 16:26 safemode_count_rec_com.tencent.mm:cuploader
    -rw------- 1 u0_a211 u0_a211 42 2021-12-22 08:56 safemode_count_rec_com.tencent.mm:push
    -rw------- 1 u0_a211 u0_a211 42 2021-12-21 16:27 safemode_count_rec_com.tencent.mm:recovery
    -rw------- 1 u0_a211 u0_a211 42 2021-12-21 17:32 safemode_count_rec_com.tencent.mm:sandbox

    => 里面的內容包含tinker_classN.apk還有odex/vdex/art/so等文件,目前tinker已經是微信優化過后的了,
    不過由于文件比較大還是會導致,相當于加載2次dex文件,針對低配置的手機影響還是很容易看出來的。(相當于2次冷啟動)

    0 /data/user/0/com.tencent.mm/tinker/info.lock
    8.4M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/patch-66e50d2a.apk
    36K /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/oat/tinker_classN.apk.cur.prof
    2.6M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/oat/arm/tinker_classN.vdex
    8.1M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/oat/arm/tinker_classN.odex
    2.8M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/oat/arm/tinker_classN.art
    14M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/oat/arm
    64K /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/oat/tinker_classN.apk.prof
    14M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/oat
    132M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/tinker_classN.apk
    146M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex
    3.5K /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/odex
    3.7M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/lib/lib/armeabi-v7a/libliteavsdk.so
    9.4M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/lib/lib/armeabi-v7a/libapp.so
    6.3M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/lib/lib/armeabi-v7a/libflutter.so
    1.1M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/lib/lib/armeabi-v7a/libwechatlv.so
    21M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/lib/lib/armeabi-v7a
    21M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/lib/lib
    21M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/lib
    68M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/res/resources.apk
    68M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a/res
    243M /data/user/0/com.tencent.mm/tinker/patch-66e50d2a
    4.0K /data/user/0/com.tencent.mm/tinker/patch.info
    4.0K /data/user/0/com.tencent.mm/tinker/safemode_count_rec_com.tencent.mm
    4.0K /data/user/0/com.tencent.mm/tinker/safemode_count_rec_com.tencent.mm:push
    4.0K /data/user/0/com.tencent.mm/tinker/safemode_count_rec_com.tencent.mm:appbrand1
    4.0K /data/user/0/com.tencent.mm/tinker/safemode_count_rec_com.tencent.mm:appbrand0
    4.0K /data/user/0/com.tencent.mm/tinker/safemode_count_rec_com.tencent.mm:sandbox
    4.0K /data/user/0/com.tencent.mm/tinker/safemode_count_rec_com.tencent.mm:cuploader
    4.0K /data/user/0/com.tencent.mm/tinker/safemode_count_rec_com.tencent.mm:recovery
    243M /data/user/0/com.tencent.mm/tinker/

    ps:
    之前舊版本的tinker(2020年6月),tinker目錄里面只有一個熱更新的apk,會更加慢

    $ tinker$ du -ah

    5.1M ./patch-66490a13/patch-66490a13.apk
    4.0K ./patch-66490a13/odex
    3.9M ./patch-66490a13/lib/lib/armeabi-v7a/libmagicbrush.so
    3.4M ./patch-66490a13/lib/lib/armeabi-v7a/libliteavsdk.so
    476K ./patch-66490a13/lib/lib/armeabi-v7a/libwechatsight_v7a.so
    11M ./patch-66490a13/lib/lib/armeabi-v7a/libapp.so
    19M ./patch-66490a13/lib/lib/armeabi-v7a
    19M ./patch-66490a13/lib/lib
    19M ./patch-66490a13/lib
    83M ./patch-66490a13/dex/tinker_classN.apk
    44K ./patch-66490a13/dex/oat/tinker_classN.apk.cur.prof
    48K ./patch-66490a13/dex/oat
    83M ./patch-66490a13/dex
    48M ./patch-66490a13/res/resources.apk
    48M ./patch-66490a13/res
    154M ./patch-66490a13
    0 ./info.lock
    4.0K ./patch.info
    154M .

    3. tinker對冷啟動時間的影響

    => 帶有tinker,驗證一下wm_activity_launch_time這個時間,大概在4s左右

    I wm_activity_launch_time: [0,263586177,com.tencent.mm/.app.WeChatSplashActivity,4071]
    I wm_activity_launch_time: [0,225687646,com.tencent.mm/.app.WeChatSplashActivity,4032]

    => 手動刪除整個tinker,驗證時間明顯減少,那么Android S上微信還是會導致啟動時間變慢的問題

    1317 1408 I wm_activity_launch_time: [0,244922921,com.tencent.mm/.app.WeChatSplashActivity,2158]
    1317 1408 I wm_activity_launch_time: [0,216957026,com.tencent.mm/.app.WeChatSplashActivity,2108]

    4. 修改方案

    1、加載dex流程中阻斷,如在systrace中的OpenDexFilesFromOat,如果不加載/data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/tinker_classN.apk,
    如果在art中修改
    OatFileManager::OpenDexFilesFromOat或者更下面的ArtDexFileLoader::OpenZip/ArtDexFileLoader::OpenAllDexFilesFromZip都是可以阻斷其打開流程

    識別出tinker直接跳過,如下是在OpenAllDexFilesFromZip中跳過(這個方案只在Android S之前有效,Android S的正常android版本中art已經給mainline,使用的是gms里面的art)

    //art/libdexfile/dex/art_dex_file_loader.cc bool ArtDexFileLoader::OpenAllDexFilesFromZip(const ZipArchive& zip_archive,const std::string& location,bool verify,bool verify_checksum,std::string* error_msg,std::vector<std::unique_ptr<const DexFile>>* dex_files) const {ScopedTrace trace("Dex file open from Zip " + std::string(location)); //...//識別location是否包含tinkerif (hasTinker) {//包含則跳過return false;} //... }

    2、那么Android S現在art修改方案無效,我們怎么做呢?
    還是那句話:先調查清楚,再來動筆

    5. Open Dex是什么時候觸發的?其中傳入的location又是那里來的?

    1、從OatFileManager::OpenDexFilesFromOat往上找
    //

    art/runtime/native/dalvik_system_DexFile.ccstatic jobject DexFile_openDexFileNative(JNIEnv* env,jclass,jstring javaSourceName,jstring javaOutputName ATTRIBUTE_UNUSED,jint flags ATTRIBUTE_UNUSED,jobject class_loader,jobjectArray dex_elements) {ScopedUtfChars sourceName(env, javaSourceName);if (sourceName.c_str() == nullptr) {return nullptr;}std::vector<std::string> error_msgs;const OatFile* oat_file = nullptr;std::vector<std::unique_ptr<const DexFile>> dex_files =Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(sourceName.c_str(),class_loader,dex_elements,/*out*/ &oat_file,/*out*/ &error_msgs);return CreateCookieFromOatFileManagerResult(env, dex_files, oat_file, error_msgs); }//這是一個jni過來的方法 static JNINativeMethod gMethods[] = {NATIVE_METHOD(DexFile, openDexFileNative,"(Ljava/lang/String;""Ljava/lang/String;""I""Ljava/lang/ClassLoader;""[Ldalvik/system/DexPathList$Element;"")Ljava/lang/Object;"),

    2、這里上一級目錄在libcore中libcore/dalvik/src/main/java/dalvik/system/DexFile.java,
    在創建DexFile對象的時候就會打開dex file

    private static Object openDexFile(String sourceName, String outputName, int flags,ClassLoader loader, DexPathList.Element[] elements) throws IOException {// Use absolute paths to enable the use of relative paths when testing on host.return openDexFileNative(new File(sourceName).getAbsolutePath(),(outputName == null)? null: new File(outputName).getAbsolutePath(),flags,loader,elements);}private DexFile(String sourceName, String outputName, int flags, ClassLoader loader,DexPathList.Element[] elements) throws IOException {//...mCookie = openDexFile(sourceName, outputName, flags, loader, elements);mInternalCookie = mCookie;mFileName = sourceName;//System.out.println("DEX FILE cookie is " + mCookie + " sourceName=" + sourceName + " outputName=" + outputName);}

    3、搜索new DexFile,只有DexPathList.java、DexFile.java才new了DexFile對象

    libcore/dalvik$ grep -rn “new DexFile” .
    ./src/main/java/dalvik/system/DexPathList.java:268: DexFile dex = new DexFile(dexFiles, definingContext, null_elements);
    ./src/main/java/dalvik/system/DexPathList.java:347: DexFile dex = new DexFile(new ByteBuffer[] { buf }, /* classLoader */ null,
    ./src/main/java/dalvik/system/DexPathList.java:442: return new DexFile(file, loader, elements);
    ./src/main/java/dalvik/system/DexFile.java:216: return new DexFile(sourcePathName, outputPathName, flags, loader, elements);

    DexPathList(ClassLoader definingContext, String dexPath,String librarySearchPath, File optimizedDirectory, boolean isTrusted) {//...// save dexPath for BaseDexClassLoaderthis.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,suppressedExceptions, definingContext, isTrusted);//...}private static Element[] makeDexElements(List<File> files, File optimizedDirectory,List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) {//...dex = loadDexFile(file, optimizedDirectory, loader, elements);//...}private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader,Element[] elements)throws IOException {if (optimizedDirectory == null) {//初始化時這個是nullreturn new DexFile(file, loader, elements);} else {String optimizedPath = optimizedPathFor(file, optimizedDirectory);return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader, elements);//打開微信***.apk走的是這里}}

    4、往上找關聯流程

    這里就直接找到LoadedApk.java,這里是App加載apk的地方,流程從這里往第3點找

    //frameworks/base/core/java/android/app/LoadedApk.javapublic ClassLoader getClassLoader() {synchronized (mLock) {if (mClassLoader == null) {createOrUpdateClassLoaderLocked(null /*addedPaths*/);}return mClassLoader;}}private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {//..//mApplicationInfo.sourceDir就是/data/app/***/com.tencent.mm***/base.apkmakePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);//...final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :TextUtils.join(File.pathSeparator, zipPaths);//zip就是/data/app/***/com.tencent.mm***/base.apk//...if (mDefaultClassLoader == null) {//...//創建mDefaultClassLoadermDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,libraryPermittedPath, mBaseClassLoader,mApplicationInfo.classLoaderName, sharedLibraries, nativeSharedLibraries);//微信的mAppComponentFactory = androidx.core.app.CoreComponentFactorymAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);//...}//...if (mClassLoader == null) {//通過mAppComponentFactory創建mClassLoadermClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader,new ApplicationInfo(mApplicationInfo));}}

    繼續看一下ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries

    //frameworks/base/core/java/android/app/ApplicationLoaders.javaClassLoader getClassLoaderWithSharedLibraries(String zip, int targetSdkVersion, boolean isBundled,String librarySearchPath, String libraryPermittedPath,ClassLoader parent, String classLoaderName,List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) {// For normal usage the cache key used is the same as the zip path.return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries,nativeSharedLibraries);}private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,String librarySearchPath, String libraryPermittedPath,ClassLoader parent, String cacheKey,String classLoaderName, List<ClassLoader> sharedLibraries,List<String> nativeSharedLibraries) {//...ClassLoader classloader = ClassLoaderFactory.createClassLoader(zip, librarySearchPath, libraryPermittedPath, parent,targetSdkVersion, isBundled, classLoaderName, sharedLibraries,nativeSharedLibraries);//注意傳入的參數zip即可//...}//frameworks/base/core/java/com/android/internal/os/ClassLoaderFactory.java public static ClassLoader createClassLoader(String dexPath,String librarySearchPath, String libraryPermittedPath, ClassLoader parent,int targetSdkVersion, boolean isNamespaceShared, String classLoaderName,List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) {final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent,classLoaderName, sharedLibraries);//...}public static ClassLoader createClassLoader(String dexPath,String librarySearchPath, ClassLoader parent, String classloaderName,List<ClassLoader> sharedLibraries) {ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null)? null: sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]);ClassLoader result = null;//一般由于mApplicationInfo.classLoaderName沒有設置,故默認創建的都是PathClassLoaderif (isPathClassLoaderName(classloaderName)) {return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries);} else if (isDelegateLastClassLoaderName(classloaderName)) {//如果有設置classloaderName = "dalvik.system.DelegateLastClassLoader"則進入這里return new DelegateLastClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries);}throw new AssertionError("Invalid classLoaderName: " + classloaderName);}

    5、我們到了另外代碼文件目錄libcore/dalvik/,繼續查看libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java

    //libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.javapublic PathClassLoader(@NonNull String dexPath, @Nullable String librarySearchPath, @Nullable ClassLoader parent,@Nullable ClassLoader[] sharedLibraryLoaders) {super(dexPath, librarySearchPath, parent, sharedLibraryLoaders);}//libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.javapublic BaseDexClassLoader(String dexPath,String librarySearchPath, ClassLoader parent, ClassLoader[] libraries) {this(dexPath, librarySearchPath, parent, libraries, false);}public BaseDexClassLoader(String dexPath,String librarySearchPath, ClassLoader parent, ClassLoader[] sharedLibraryLoaders,boolean isTrusted) {super(parent);// Setup shared libraries before creating the path list. ART relies on the class loader// hierarchy being finalized before loading dex files.this.sharedLibraryLoaders = sharedLibraryLoaders == null? null: Arrays.copyOf(sharedLibraryLoaders, sharedLibraryLoaders.length);//注意此處開始構建new DexPathList//dexPath就是/data/app/***/com.tencent.mm***/base.apkthis.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);// Run background verification after having set 'pathList'.this.pathList.maybeRunBackgroundVerification(this);reportClassLoaderChain();}//libcore/dalvik/src/main/java/dalvik/system/DexPathList.java//這里就回到了這個章節的第3點DexPathList(ClassLoader definingContext, String dexPath,String librarySearchPath, File optimizedDirectory, boolean isTrusted) {//...// save dexPath for BaseDexClassLoaderthis.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,suppressedExceptions, definingContext, isTrusted);//...}

    6、到這里基本上可以理清楚

  • Open Dex是什么時候觸發的? => 在創建初始化ClassLoader的時候會觸發
  • 其中傳入的location又是那里來的? => 這個就是DexPathList,對應zip file,如***.apk
  • 6. 斷點看一下帶tinker和不帶tinker的ClassLoader

  • 設置微信斷點位置
  • //frameworks/base/core/java/android/app/LoadedApk.javapublic ClassLoader getClassLoader() {synchronized (mLock) {if (mClassLoader == null) {//可以在這里設置斷點位置createOrUpdateClassLoaderLocked(null /*addedPaths*/);}return mClassLoader;}}
  • 默認安裝后不帶tinker的ClassLoader
    打開的dex文件就是/data/app/***/com.tencent.mm***/base.apk,微信默認安裝的apk
  • mClassLoader = {PathClassLoader@33282} “dalvik.system.PathClassLoader[DexPathList[[zip file “/data/app/~~IhVsaxjwrzj_c6zzMznrww==/com.tencent.mm-hX9AatQT4nETNnGgbug_GA==/base.apk”],nativeLibraryDirectories=[/data/app/~~IhVsaxjwrzj_c6zzMznrww==/com.tencent.mm-hX9AatQT4nETNnGgbug_GA==/lib/arm, /data/app/~~IhVsaxjwrzj_c6zzMznrww==/com.tencent.mm-hX9AatQT4nETNnGgbug_GA==/base.apk!/lib/armeabi-v7a, /system/lib, /system/system_ext/lib]]]”

  • 帶有tinker的ClassLoader,但是默認的PathClassLoader其實也是創建的,相當于創建了2個ClassLoader(注意此處需要載入2個apk,本身需要的時間就會變長)
    可以看到打開的dex文件就是/data/user/0/com.tencent.mm/tinker/patch-***/dex/tinker_classN.apk,這個就是微信熱更新里面的tinker文件,而不是我們一開始安裝的文件
  • mClassLoader = {DelegateLastClassLoader@15795} “dalvik.system.DelegateLastClassLoader[DexPathList[[zip file “/data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/tinker_classN.apk”],nativeLibraryDirectories=[/data/user/0/com.tencent.mm/tinker/patch-66e50d2a/lib/lib/armeabi-v7a, /data/app/~~Gcugv7eeiy5Og6ory1jVrg==/com.tencent.mm-OKmJgE3WNLcG_AaLmxxzw==/lib/arm, /data/app/~~Gldgv7eeiy5Og6ory1jVrg==/com.tencent.mm-OKmJgE3WNLcG_AaLmxxzw==/base.apk!/lib/armeabi-v7a, /system/lib, /system/system_ext/lib]]]”
    parent = {PathClassLoader@125091} “dalvik.system.PathClassLoader[DexPathList[[zip file “/data/app/~~IhVsaxjwrzj_c6zzMznrww==/com.tencent.mm-hX9AatQT4nETNnGgbug_GA==/base.apk”],nativeLibraryDirectories=[/data/app/~~IhVsaxjwrzj_c6zzMznrww==/com.tencent.mm-hX9AatQT4nETNnGgbug_GA==/lib/arm, /data/app/~~Gldgv7eeiy5Og6ory1jVrg==/com.tencent.mm-hX9AatQT4nETNnGgbug_GA==/base.apk!/lib/armeabi-v7a, /system/lib, /system/system_ext/lib]]]”

    7. 微信內部tinker加載的流程

    那么一個簡單的想法就是在微信設置DelegateLastClassLoader的時候還原成PathClassLoader,但是如果只修改LoadedApk.java,
    你會發現會導致微信崩潰,也就是說修改不完善,還有別的初始化內容沒有還原

    public ClassLoader getClassLoader() {synchronized (mLock) {if (mClassLoader == null) {createOrUpdateClassLoaderLocked(null /*addedPaths*/);}// yunhen test startif (mResDir != null && mResDir.contains("tinker")) {mClassLoader = mDefaultClassLoader;if(mSourceDir != null) {mResDir = mSourceDir;}}// yunhen test endreturn mClassLoader;}}

    繼續在系統所有mClassLoader =的地方添加日志,發現根本就沒有跑系統代碼,
    那只能是app本身調用的函數注入、反射等來實現設置的功能,這樣問題就比調用系統方法復雜。

    1、分析三方應用有多種方法,如反編譯工具
    jadx-gui-***.exe、jd-gui.exe => 這個可以直接得到java代碼,比較容易看,不過缺點是部分代碼轉換失敗
    java -jar apktool_***.jar d + 路徑 => 這個是反編譯成class,并將class轉換成smali,不太好看(主要應該是不習慣,看得少),但是不會漏掉

    2、反編譯之后看流程

    源碼中從handleBindApplication開始,到Application.java的attach后進入微信重載流程
    handleBindApplication(ActivityThread.java)->makeApplication(LoadedApk.java)->newApplication(Instrumentation.java)->attach(Application.java)

    下面將這些流程貼一下
    attach(Application.java) -> attachBaseContext/onBaseContextAttached/loadTinker(TinkerApplication.java) -> tryLoad/tryLoadPatchFilesInternal(判斷是否存在tinker的各類文件,patch.info(getPatchInfoFile)在這里判斷)(TinkerLoader.java) -> loadTinkerJars(TinkerDexLoader.java) -> installDexes(SystemClassLoaderAdder.java) -> inject(NewClassLoaderInjector.java) ->createNewClassLoader/doInject(NewClassLoaderInjector.java) -> Thread setContextClassLoader/ContextWrapper mBase mClassLoader/ContextImpl mPackageInfo mClassLoader

    //frameworks/base/core/java/android/app/Application.java/* package */ final void attach(Context context) {attachBaseContext(context);mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;}// Application.java package com.tencent.mm.app;import com.tencent.tinker.loader.app.TinkerApplication;public class Application extends TinkerApplication {private static final String TINKER_LOADER_ENTRY_CLASSNAME = "com.tencent.tinker.loader.TinkerLoader";private static final String WECHAT_APPLICATION_LIKE_CLASSNAME = "com.tencent.mm.app.MMApplicationLike";public Application() {//微信的TinkerLoader(TINKER_LOADER_ENTRY_CLASSNAME = com.tencent.tinker.loader.TinkerLoader),同時7代表tinkerFlagssuper(7, WECHAT_APPLICATION_LIKE_CLASSNAME, TINKER_LOADER_ENTRY_CLASSNAME, true, true);} }//TinkerApplication.java package com.tencent.tinker.loader.app;protected TinkerApplication(int i, String str, String str2, boolean z, boolean z2) {this.mCurrentClassLoader = null;this.mInlineFence = null;synchronized (SELF_HOLDER) {SELF_HOLDER[0] = this;}this.tinkerFlags = i;this.delegateClassName = str;this.loaderClassName = str2;this.tinkerLoadVerifyFlag = z;this.useDelegateLastClassLoader = z2;}public void attachBaseContext(Context context) {super.attachBaseContext(context);long elapsedRealtime = SystemClock.elapsedRealtime();long currentTimeMillis = System.currentTimeMillis();Thread.setDefaultUncaughtExceptionHandler(new TinkerUncaughtHandler(this));onBaseContextAttached(context, elapsedRealtime, currentTimeMillis);//這里是tinker的下一步流程}public void onBaseContextAttached(Context context, long j, long j2) {try {loadTinker();//加載微信tinkerthis.mCurrentClassLoader = context.getClassLoader();//此處已經是加載過后,ClassLoader變成了tinker的ClassLoaderthis.mInlineFence = createInlineFence(this, this.tinkerFlags, this.delegateClassName, this.tinkerLoadVerifyFlag, j, j2, this.tinkerResultIntent);TinkerInlineFenceAction.callOnBaseContextAttached(this.mInlineFence, context);if (this.useSafeMode) {ShareTinkerInternals.setSafeModeCount(this, 0);}} catch (TinkerRuntimeException e2) {throw e2;} catch (Throwable th) {throw new TinkerRuntimeException(th.getMessage(), th);}}private static final String TINKER_LOADER_METHOD = "tryLoad";private void loadTinker() {try {Class<?> cls = Class.forName(this.loaderClassName, false, TinkerApplication.class.getClassLoader());//調用的是TinkerLoader的tryLoad的方法(用的反射調用,應該是tinker是一個公共組件才這么做)this.tinkerResultIntent = (Intent) cls.getMethod(TINKER_LOADER_METHOD, TinkerApplication.class).invoke(cls.getConstructor(new Class[0]).newInstance(new Object[0]), this);} catch (Throwable th) {this.tinkerResultIntent = new Intent();ShareIntentUtil.setIntentReturnCode(this.tinkerResultIntent, -20);this.tinkerResultIntent.putExtra("intent_patch_exception", th);}}//ShareTinkerInternals.javapublic static boolean isTinkerEnabled(int i) {return i != 0;}//TinkerLoader.javapublic Intent tryLoad(TinkerApplication tinkerApplication) {ShareTinkerLog.d(TAG, "tryLoad test test", new Object[0]);Intent intent = new Intent();long elapsedRealtime = SystemClock.elapsedRealtime();tryLoadPatchFilesInternal(tinkerApplication, intent);ShareIntentUtil.setIntentPatchCostTime(intent, SystemClock.elapsedRealtime() - elapsedRealtime);return intent;}private void tryLoadPatchFilesInternal(com.tencent.tinker.loader.app.TinkerApplication r22, android.content.Intent r23) {/*// Method dump skipped, instructions count: 1301 這里反編譯失敗,通過apktool去拿到TinkerLoader.smali可以看到里面的虛擬機代碼*/throw new UnsupportedOperationException("Method not decompiled: com.tencent.tinker.loader.TinkerLoader.tryLoadPatchFilesInternal(com.tencent.tinker.loader.app.TinkerApplication, android.content.Intent):void");.locals 21.prologue.line 64invoke-virtual/range {p1 .. p1}, Lcom/tencent/tinker/loader/app/TinkerApplication;->getTinkerFlags()I //獲取tinkerFlagsmove-result v6.line 66invoke-static {v6}, Lcom/tencent/tinker/loader/shareutil/ShareTinkerInternals;->isTinkerEnabled(I)Z //調用isTinkerEnabled判斷是否需要支持tinkermove-result v2if-nez v2, :cond_0 //nez(not equal zero),如果tinkerFlags不為0,則v2=true進入cond_0,否則v2=false,進入下面邏輯,.line 67const-string/jumbo v2, "Tinker.TinkerLoader"const-string/jumbo v3, "tryLoadPatchFiles: tinker is disable, just return" //這里描述也很清楚,tinker不支持,返回不走tinker流程const/4 v4, 0x0new-array v4, v4, [Ljava/lang/Object;invoke-static {v2, v3, v4}, Lcom/tencent/tinker/loader/shareutil/ShareTinkerLog;->w(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V.line 68const/4 v2, -0x1move-object/from16 v0, p2invoke-static {v0, v2}, Lcom/tencent/tinker/loader/shareutil/ShareIntentUtil;->setIntentReturnCode(Landroid/content/Intent;I)V.line 392:goto_0return-void //...不關注的流程我們跳過吧,這里只是目的告知大家方法和自己記錄一下分析過程,不是去剖析微信代碼 //后面判斷是否在做tinker的過程中、是否存在tinker目錄 //其中tinker的目錄的邏輯,一般是在applicationInfo.dataDir的tinker目錄,如Android S的/data/user/0/com.tencent.mm/tinker,微信針對oppo特殊做了手腳,放在wc_tinker_dir //如果不存在tinker目錄,不走tinker流程,此處直接返回public static final String PATCH_DIRECTORY_NAME = "tinker";public static final String PATCH_DIRECTORY_NAME_SPEC = "wc_tinker_dir";public static File getPatchDirectory(Context context) {ApplicationInfo applicationInfo = context.getApplicationInfo();if (applicationInfo == null) {return null;}return new File(applicationInfo.dataDir, (!"oppo".equalsIgnoreCase(Build.MANUFACTURER) || Build.VERSION.SDK_INT != 22) ? ShareConstants.PATCH_DIRECTORY_NAME : ShareConstants.PATCH_DIRECTORY_NAME_SPEC);} //... //這里有判斷/data/user/0/com.tencent.mm/tinker/patch.info是否存在,如果不存在則不走tinker流程:cond_3invoke-static {v10}, Lcom/tencent/tinker/loader/shareutil/SharePatchFileUtil;->getPatchInfoFile(Ljava/lang/String;)Ljava/io/File; /*public static File getPatchInfoFile(String str) {return new File(str + "/patch.info");} */move-result-object v11.line 97invoke-virtual {v11}, Ljava/io/File;->exists()Zmove-result v2if-nez v2, :cond_4.line 98const-string/jumbo v2, "Tinker.TinkerLoader"new-instance v3, Ljava/lang/StringBuilder;const-string/jumbo v4, "tryLoadPatchFiles:patch info not exist:" //patch.info文件不存在 //... goto/16 :goto_0.line 104 //... info.lock是PatchInfo同步鎖,防止讀取時多線程邏輯異常//... 讀取patchInfo的信息,如識別的目的主要是為了選取patch-66e50d2a目錄的內容//... 其它如intent_is_protected_app設置,版本識別(識別異常則返回,成功會將舊的tinker(如果有多個tinker的話)刪除)、檢查tinker ota文件是否正確是否需要重新生成,一堆異常處理 //... isTinkerEnabledForResource是否需要加載/data/user/0/com.tencent.mm/tinker/patch***/res/resources.apk // (loadTinkerResources除了會設置resources.apk, 還會對設置mResDir/publicSourceDir = "/data/user/0/com.tencent.mm/tinker/patch-***/res/resources.apk"),addAssetPath/mAssets等資源相關 /* 各類需要加載的內容默認i=7, 也就是isTinkerEnabledForDex、isTinkerEnabledForNativeLib、isTinkerEnabledForResource返回truepublic static boolean isTinkerEnabledForDex(int i) {return (i & 1) != 0;}public static boolean isTinkerEnabledForNativeLib(int i) {return (i & 2) != 0;}public static boolean isTinkerEnabledForResource(int i) {return (i & 4) != 0;}public static boolean isTinkerEnabledForArkHot(int i) {return (i & 8) != 0;} */ //...:cond_1cif-nez v17, :cond_1f //v17是isArkHotRuning針對huawei做的適配,一般都是falseif-eqz v16, :cond_1f //v16是isTinkerEnabledForDex的結果不為0move-object/from16 v2, p1move-object/from16 v5, p2.line 325//這個是調用加載tinker的下一步loadTinkerJarsinvoke-static/range {v2 .. v7}, Lcom/tencent/tinker/loader/TinkerDexLoader;->loadTinkerJars(Lcom/tencent/tinker/loader/app/TinkerApplication;Ljava/lang/String;Ljava/lang/String;Landroid/content/Intent;ZZ)Zmove-result v4.line 327if-eqz v6, :cond_29//TinkerDexLoader.javapublic static boolean loadTinkerJars(TinkerApplication tinkerApplication, String str, String str2, Intent intent, boolean z, boolean z2) {if (!LOAD_DEX_LIST.isEmpty() || !classNDexInfo.isEmpty()) {ClassLoader classLoader = TinkerDexLoader.class.getClassLoader();if (classLoader != null) {//...if (isVmArt && !classNDexInfo.isEmpty()) {android S上, isVmArt = true//file2就是data/user/0/com.tencent.mm/tinker/patch-***/dex/tinker_classN.apkFile file2 = new File(str3 + ShareConstants.CLASS_N_APK_NAME);//CLASS_N_APK_NAME = "tinker_classN.apk";//...arrayList.add(file2);}//...if (z) {//...//微信也可以手動調用dex2oat,目前這個沒跑,tinker_classN.odex應該是下載的TinkerDexOptimizer.optimizeAll(tinkerApplication, arrayList, file4, true, tinkerApplication.isUseDelegateLastClassLoader(), currentInstructionSet, new TinkerDexOptimizer.ResultCallback() {//...}try {//installDexes是tinker的下一步流程, arrayList包含tinker_classN.apkSystemClassLoaderAdder.installDexes(tinkerApplication, classLoader, file3, arrayList, z2, tinkerApplication.isUseDelegateLastClassLoader());return true;//...}//SystemClassLoaderAdder.javapublic static void installDexes(Application application, ClassLoader classLoader, File file, List<File> list, boolean z, boolean z2) {ShareTinkerLog.i(TAG, "installDexes dexOptDir: " + file.getAbsolutePath() + ", dex size:" + list.size(), new Object[0]);if (!list.isEmpty()) {List<File> createSortedAdditionalPathEntries = createSortedAdditionalPathEntries(list);if (Build.VERSION.SDK_INT < 24 || z) {injectDexesInternal(classLoader, createSortedAdditionalPathEntries, file);} else {//Android S走的是這里,注入,其實就是反射調用系統代碼, createSortedAdditionalPathEntries包含tinker_classN.apkclassLoader = NewClassLoaderInjector.inject(application, classLoader, file, z2, createSortedAdditionalPathEntries);}sPatchDexCount = createSortedAdditionalPathEntries.size();ShareTinkerLog.i(TAG, "after loaded classloader: " + classLoader + ", dex size:" + sPatchDexCount, new Object[0]);if (!checkDexInstall(classLoader)) {uninstallPatchDex(classLoader);throw new TinkerRuntimeException(ShareConstants.CHECK_DEX_INSTALL_FAIL);}}}//NewClassLoaderInjector.javapublic static ClassLoader inject(Application application, ClassLoader classLoader, File file, boolean z, List<File> list) {String[] strArr = new String[list.size()];for (int i = 0; i < strArr.length; i++) {strArr[i] = list.get(i).getAbsolutePath();//此流程中strArr包含tinker_classN.apk}//眾里尋他千百度,終于來了,createNewClassLoader創建ClassLoaderClassLoader createNewClassLoader = createNewClassLoader(classLoader, file, z, true, strArr);//將新的class loader反射設置到系統中去doInject(application, createNewClassLoader);return createNewClassLoader;}private static ClassLoader createNewClassLoader(ClassLoader classLoader, File file, boolean z, boolean z2, String... strArr) {List<File> list;ClassLoader tinkerClassLoader;Object obj = findField(Class.forName("dalvik.system.BaseDexClassLoader", false, classLoader), "pathList").get(classLoader);StringBuilder sb = new StringBuilder();if (strArr != null && strArr.length > 0) {for (int i = 0; i < strArr.length; i++) {if (i > 0) {sb.append(File.pathSeparator);}sb.append(strArr[i]);}}String sb2 = sb.toString();//此流程中sb2包含tinker_classN.apkField findField = findField(obj.getClass(), "nativeLibraryDirectories");if (findField.getType().isArray()) {list = Arrays.asList((File[]) findField.get(obj));} else {list = (List) findField.get(obj);}StringBuilder sb3 = new StringBuilder();boolean z3 = true;for (File file2 : list) {if (file2 != null) {if (z3) {z3 = false;} else {sb3.append(File.pathSeparator);}sb3.append(file2.getAbsolutePath());}}String sb4 = sb3.toString();if (!z || Build.VERSION.SDK_INT < 27) {tinkerClassLoader = new TinkerClassLoader(sb2, file, sb4, classLoader);} else {//目前Android S中微信使用的是DelegateLastClassLoader//DelegateLastClassLoader(String dexPath, String librarySearchPath, ClassLoader parent)//sb2是dexPath包含tinker_classN.apktinkerClassLoader = new DelegateLastClassLoader(sb2, sb4, ClassLoader.getSystemClassLoader());Field declaredField = ClassLoader.class.getDeclaredField("parent");declaredField.setAccessible(true);//設置DelegateLastClassLoader(DexPathList是/data/user/**)的parent是原來的PathClassLoader(DexPathList是/data/app**)declaredField.set(tinkerClassLoader, classLoader);}if (z2 && Build.VERSION.SDK_INT < 26) {findField(obj.getClass(), "definingContext").set(obj, tinkerClassLoader);}return tinkerClassLoader;}private static void doInject(Application application, ClassLoader classLoader) {Thread.currentThread().setContextClassLoader(classLoader);Context context = (Context) findField(application.getClass(), "mBase").get(application);//ContextWrapper mBasetry {findField(context.getClass(), "mClassLoader").set(context, classLoader);//將tinker的ClassLoader賦值給ContextImpl mClassLoader} catch (Throwable th) {}Object obj = findField(context.getClass(), "mPackageInfo").get(context);//ContextImpl mPackageInfofindField(obj.getClass(), "mClassLoader").set(obj, classLoader);//將tinker的ClassLoader賦值給ContextImpl mPackageInfoif (Build.VERSION.SDK_INT < 27) { //Android S SDK_INT > 27不跑這里Resources resources = application.getResources();//ContextImpl public Resources getResources() {return mResources;}try {findField(resources.getClass(), "mClassLoader").set(resources, classLoader);//Resources mClassLoaderObject obj2 = findField(resources.getClass(), "mDrawableInflater").get(resources);//DrawableInflater mDrawableInflaterif (obj2 != null) {findField(obj2.getClass(), "mClassLoader").set(obj2, classLoader);//DrawableInflater private final ClassLoader mClassLoader;}} catch (Throwable th2) {}}}

    8. Android S優化tinker導致啟動慢的方案

    1、參考Google play,不允許tinker其實功能還是可以正常運行的,那就還是限制tinker使用方面去。

    2、重新做一次其針對該手機的dex優化,例如在新增known secondary dex files的時候,做一次dexOptSecondaryDexPathLI,
    插莊的位置可以放在notifyDexLoadInternal。不過這個會涉及一系列問題,有多種場景可能會導致patch失效。(微信最新版本有odex文件的情況下提升不是很大)

    Dexopt state:[com.tencent.mm]path: /data/app/~~Gldgv7eeiy5Og6ory1jVrg==/com.tencent.mm-OKmJgE3WNLcG_AbdLmxxzw==/base.apkarm: [status=verify] [reason=install]known secondary dex files:/data/user/0/com.tencent.mm/app_xwalk_3164/apk/base.apkclass loader context: PCL[];PCL[]/data/user/0/com.tencent.mm/tinker/patch-66e50d2a/dex/tinker_classN.apkclass loader context: DLC[];PCL[]/data/user/0/com.tencent.mm/app_xwalkplugin/XFilesPPTReader_338/extracted/pptreader.apk

    3、限制tinker其實也是有很多種方法,通過上面的流程分析,可以在任意一段代碼卡住tinker流程即可。

  • Android S之前,如Anroid O、P、Q、R等,可以直接在art中跳過
  • Android S main line art之后,可以考慮上面tinker的一些判斷,主要是tryLoadPatchFilesInternal里面
    如不讓tinker下載(com.tencent.mm:patch進程啟動com.tencent.mm/com.tencent.tinker.lib.service.TinkerPatchForeService}服務下載的)、或者tinker apk下載后刪除、或者阻斷tinker的識別patch.info等
  • 可以將微信設置tinker后馬上還原即可, 如章節7里面的嘗試繼續根據反編譯看到的流程里面做完善(不僅僅LoadedApk.java,還有Thread、ContextImpl也需要修改,包括resource相關也需要改回去,甚至包含微信內部的邏輯也需要考慮)
  • 這樣一看,貌似還是2更簡單一點。

    最后提供一個思路,其實將patch.info刪除即可(其它騰訊系或者使用tinker的apk都可以用這類方法),刪除的位置可以放在handleBindApplication(ActivityThread.java)調用makeApplication(LoadedApk.java)之前即可
    至于其它方法這里就不繼續討論了,各位有興趣自己嘗試一下

    private void handleBindApplication(AppBindData data) {// ...try {File tinker = new File("/data/user/0/com.tencent.mm/tinker/patch.info");if (tinker.exists()) {tinker.delete();}} catch (Exception e) {Slog.w(TAG, "tinker.delete Exception e = " + e);}// ...try {// If the app is being launched for full backup or restore, bring it up in// a restricted environment with the base application class.app = data.info.makeApplication(data.restrictedBackupMode, null);//放著這里之前就行了

    總結

    以上是生活随笔為你收集整理的微信tinker导致冷启动变慢的问题优化的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    午夜性福利 | 色综合天天综合在线视频 | 国产99久久精品一区二区300 | 午夜视频一区二区三区 | 亚洲一区二区三区精品在线观看 | 在线看国产日韩 | 成人动漫视频在线 | 中文字幕精品www乱入免费视频 | 亚洲砖区区免费 | 精品福利在线视频 | 久久电影国产免费久久电影 | 久久成人国产精品入口 | 国产99久久九九精品免费 | 久久久久国产一区二区三区四区 | 中文字幕日韩av | 92精品国产成人观看免费 | 久久精品99国产精品亚洲最刺激 | 久久九九国产精品 | 国产 一区二区三区 在线 | 久久精品91久久久久久再现 | 高清不卡毛片 | 黄色性av| 久久久久久久国产精品 | 国产精品视频一二三 | 久久不卡视频 | 国产日本亚洲高清 | 国产精品一区二区果冻传媒 | 久久国产免费 | 日韩毛片在线一区二区毛片 | 97色在线观看 | 开心激情综合网 | 在线观看视频在线 | 91在线看黄 | 欧美作爱视频 | 一本一本久久a久久精品综合妖精 | 免费黄a| 在线小视频 | av电影在线观看完整版一区二区 | 毛片美女网站 | 97精品国产97久久久久久春色 | 亚洲 欧美变态 另类 综合 | 精品99免费| 久久综合九色综合97婷婷女人 | aaa日本高清在线播放免费观看 | 日韩在线观看视频免费 | 成人午夜网址 | 国产成人精品一区二区三区网站观看 | 日本三级香港三级人妇99 | 亚洲一区av| 91福利视频一区 | 久久久久久国产精品久久 | 日韩视频一区二区三区在线播放免费观看 | 午夜手机看片 | 成人在线观看免费视频 | 一区二区视频免费在线观看 | 亚洲热视频 | 国产97碰免费视频 | 色噜噜在线观看视频 | 黄色资源在线观看 | 日韩欧美综合 | 国产精品初高中精品久久 | 国产永久免费高清在线观看视频 | 精品国产欧美 | 激情久久婷婷 | 色播五月激情综合网 | 九九久久久 | 天天插视频 | 麻豆免费在线播放 | 欧美精品你懂的 | 天天操天天干天天玩 | 黄色电影在线免费观看 | 免费国产在线精品 | 国产精品午夜在线 | 亚洲国产精品一区二区久久hs | 热re99久久精品国产66热 | 日av免费 | 精品99免费视频 | av一级免费| 国产精品永久 | 精品一二三四五区 | 毛片一二区 | 免费网站在线观看人 | 日日夜夜狠狠操 | 欧美视屏一区二区 | 国产精品午夜免费福利视频 | 国产精品亚洲精品 | zzijzzij亚洲成熟少妇 | 日韩美女免费线视频 | 国产精品欧美一区二区 | 日日插日日干 | www黄在线| 国产精品女视频 | av免费网站 | 亚洲免费小视频 | 欧洲一区二区在线观看 | 国产精品系列在线观看 | 夜夜澡人模人人添人人看 | av电影免费观看 | 久久国产精品免费一区二区三区 | 欧美精品久久久久久 | 精品国产成人av | 91精品少妇偷拍99 | 欧美国产不卡 | 亚洲一级二级三级 | 免费在线看v | 96av在线| 玖操| 国产精品第一页在线 | 亚洲国产免费 | 久久国产综合视频 | 日日夜夜天天综合 | 99在线精品观看 | 视频精品一区二区三区 | 日韩经典一区二区三区 | 国产伦理久久精品久久久久_ | 美州a亚洲一视本频v色道 | 视频在线观看国产 | 中国成人一区 | 亚洲成人精品在线观看 | 久久黄色片子 | 国产精品av免费在线观看 | 高清av中文字幕 | 麻豆影视网站 | 六月丁香六月婷婷 | 97超碰在线视| 一区二区三区电影 | 婷婷久久婷婷 | 日韩电影一区二区在线观看 | 国产色a在线观看 | 久久久久久国产精品 | 国产精品久久99综合免费观看尤物 | 黄色在线免费观看网站 | av免费网站观看 | 午夜视频在线网站 | 成人a在线观看高清电影 | 日韩一二区在线 | 一级特黄av | 精品久久久久一区二区国产 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 天天操天天干天天操天天干 | 99久久精品国产系列 | 在线免费中文字幕 | 中文字幕一区二区三区久久 | 日韩av电影免费在线观看 | 天天操天天干天天爱 | 999色视频 | 精品国产一区二区三区在线观看 | 在线免费成人 | 亚州免费视频 | 又黄又爽的免费高潮视频 | 毛片基地黄久久久久久天堂 | 亚洲精品成人在线 | 亚洲激精日韩激精欧美精品 | 国产精品美女在线观看 | 欧美一区二区精美视频 | 国产福利久久 | 中文字幕久久精品亚洲乱码 | 国产系列精品av | 国产一区二区三区在线免费观看 | 99久久精品国产一区 | 久久av网 | 国产 一区二区三区 在线 | 日韩在线电影观看 | 日韩久久久久 | 国产精品高潮呻吟久久av无 | av日韩中文 | 免费a级毛片在线看 | 欧美综合在线观看 | 99爱视频在线观看 | www.五月天婷婷 | 亚洲免费av观看 | 久久精品福利视频 | 丁香五月亚洲综合在线 | 婷婷伊人五月天 | www久久国产 | avove黑丝| 国产老妇av | 国产在线a不卡 | 久久久久女教师免费一区 | 国产亚洲精品久久久久动 | 欧美日韩不卡一区二区 | 成人91在线| 五月天狠狠操 | 色www精品视频在线观看 | 2019中文字幕第一页 | 超碰av在线播放 | 毛片3| 午夜av色 | 色综合久久久久久久 | 午夜三级在线 | 亚洲最快最全在线视频 | 天天操天天干天天爽 | 成人免费视频视频在线观看 免费 | 亚洲精品乱码久久久久久高潮 | 久久精品官网 | 在线午夜 | 97精品国产97久久久久久春色 | 国产精品入口a级 | 久久国产精品久久精品 | 91在线在线观看 | 最新中文字幕在线观看视频 | 99久久婷婷国产综合亚洲 | 69人人| 干av在线| 亚洲精品人人 | 国产福利在线免费观看 | 国产精品久久久网站 | 在线观看的a站 | 久久在线视频在线 | 国产精品久久久久久久免费大片 | 亚洲精品中文在线 | 亚洲国产精品va在线看黑人动漫 | 久久99偷拍视频 | 91av在线电影 | 日韩精品中文字幕有码 | 美女国产免费 | 久久精品123| 免费热情视频 | 色久天 | 久久新| 999色视频 | 四虎成人在线 | 天天射天天操天天干 | 99国产一区 | 五月婷婷六月丁香在线观看 | 日韩大片免费观看 | 亚洲国产精品久久久久婷婷884 | 久久综合欧美 | 国产精品99久久久久久久久 | 日韩一区二区三区免费视频 | 波多野结衣在线播放视频 | 91成人免费观看视频 | www.五月天| 亚洲最大av网站 | 在线中文字幕av观看 | 亚洲精品中文在线 | 成人av一区二区兰花在线播放 | 98精品国产自产在线观看 | 国产一区二区综合 | 五月黄色 | 8x8x在线观看视频 | 不卡av在线播放 | 久久亚洲福利视频 | 亚洲理论电影网 | 亚洲理论电影网 | 五月婷在线 | 韩日av一区二区 | 丝袜一区在线 | 日韩在线大片 | 国产精品成人免费精品自在线观看 | 国产一区私人高清影院 | 成人永久免费 | 亚洲精品午夜久久久 | 精品成人国产 | 免费h漫在线观看 | 欧美日韩首页 | 中文字幕资源网在线观看 | 国产乱码精品一区二区三区介绍 | 国产亚洲综合精品 | 日韩黄色在线观看 | 色婷婷福利 | 婷婷中文字幕综合 | 中文字幕一区二区三区在线播放 | 91片黄在线观看 | 韩日精品在线 | 久久国产精品99久久久久久老狼 | 日本一区二区免费在线观看 | 日韩精品一区电影 | 成人四虎影院 | 91精品视频一区二区三区 | 欧美精品一级视频 | 久久草在线免费 | 欧美a免费| 欧美日韩国产一二三区 | 免费开视频 | 久久不卡免费视频 | 91视频在线国产 | 日韩有码在线观看视频 | 中文字幕精品www乱入免费视频 | 久久久久久久久久福利 | 成人在线观看影院 | 中文字幕在线视频国产 | 日韩精品一区二区三区外面 | 日本中文字幕影院 | 国产福利在线免费 | 美女黄网站视频免费 | 99精品欧美一区二区三区 | 欧美二区视频 | 97超碰在线久草超碰在线观看 | 黄色三级视频片 | 天天射天天色天天干 | 日韩激情第一页 | 三三级黄色片之日韩 | 视频二区在线视频 | 操操操av| 欧美性极品xxxx娇小 | av片子在线观看 | 久久久久久久久综合 | 视频福利在线 | 国产精品嫩草影视久久久 | 国内精品中文字幕 | 最新午夜 | 欧美久久久久久久 | 久久伊人五月天 | 少妇性aaaaaaaaa视频 | 人人澡人人舔 | 国产成人在线网站 | 久久久久久久久福利 | 久久草在线精品 | 五月婷婷中文 | 色婷婷久久久 | 91中文字幕在线视频 | 亚洲中字幕 | 欧美二区在线播放 | 深爱激情av | 婷婷丁香激情综合 | 亚洲欧美视频一区二区三区 | 蜜桃麻豆www久久囤产精品 | 国产黄a三级三级 | 人人爱人人舔 | 黄色小视频在线观看免费 | 日本中文字幕在线电影 | 在线一二三四区 | 日日夜夜天天久久 | 福利一区二区在线 | 中文字幕一区av | 久草在线资源观看 | 免费色视频| 欧美日韩高清在线 | 成人资源在线观看 | 久久九九免费 | 久久午夜电影 | 欧美久久久久久久久久久久久 | 亚洲精品国产精品久久99热 | 99亚洲国产精品 | 色噜噜在线观看 | 欧美性护士 | 久久久久夜色 | 久久国产影院 | 成人久久久久久久久久 | 嫩草91影院 | 亚洲久草网 | 久久午夜免费视频 | 人人干狠狠干 | 国产香蕉久久 | 又黄又爽又刺激的视频 | 亚洲精品国产精品乱码不99热 | 国产91精品一区二区麻豆亚洲 | 久久免费的精品国产v∧ | 日日干,天天干 | 亚洲综合在线观看视频 | 国色天香第二季 | 中文字幕视频网 | a√资源在线 | 亚洲欧美视频在线播放 | 欧美精品一区二区在线播放 | 亚洲国产精品va在线 | 天天草天天插 | 久草在线视频精品 | 夜夜夜影院 | 日韩在线观看第一页 | 天天草天天插 | 午夜国产在线观看 | 免费电影一区二区三区 | 国产99久久久久久免费看 | 精品久久久久久国产91 | 日韩av在线资源 | 伊在线视频 | 国产日韩欧美在线播放 | 日韩中文字幕电影 | 91九色综合 | 免费在线播放视频 | 久久久免费网站 | 亚洲人在线视频 | 婷婷.com| 日韩精品电影在线播放 | 天天爱天天操天天干 | 91香蕉视频720p | 久久色视频 | 美女在线免费视频 | 91porny九色91啦中文 | 免费成人在线观看视频 | 美女视频一区二区 | 毛片美女网站 | 天天干天天干天天操 | 国产韩国日本高清视频 | 国产亚洲精品免费 | 成人免费视频在线观看 | 又色又爽又黄 | 亚洲成a人片在线观看中文 中文字幕在线视频第一页 狠狠色丁香婷婷综合 | 国产成人久久av免费高清密臂 | 国产黄色av| 麻豆小视频在线观看 | 在线中文字母电影观看 | 91免费的视频在线播放 | 成人高清av在线 | 五月天精品视频 | 国产精品v a免费视频 | 国产精品国产精品 | 综合色中文 | 日韩精品在线观看av | 91精选在线观看 | 国产特级毛片aaaaaaa高清 | 鲁一鲁影院 | 在线午夜 | 免费视频国产 | 成人午夜久久 | 久热久草在线 | 91视频久久 | 99爱国产精品 | 亚洲国产97在线精品一区 | 久久久久久久久久久免费 | 激情网在线观看 | 久久r精品 | 亚洲视屏一区 | 97夜夜澡人人爽人人免费 | 免费特级黄色片 | 夜又临在线观看 | 午夜色影院 | 中文字幕国产 | 国产香蕉av | 四虎成人免费影院 | 国产美女免费视频 | 亚洲视屏一区 | 国产高清中文字幕 | 日本黄色片一区二区 | 婷婷色在线播放 | 在线观看成人小视频 | 久久小视频| 99久久精品免费视频 | 人人澡超碰碰97碰碰碰软件 | 亚洲 综合 精品 | 91桃色国产在线播放 | 国产精品一区二区av日韩在线 | 免费看片成年人 | 日韩免费在线视频观看 | 成人av影院在线观看 | 日韩亚洲欧美中文字幕 | 99成人在线视频 | 大片网站久久 | 日本中文一区二区 | 成人精品99 | 高清国产一区 | 免费在线黄色av | 天天干天天操天天 | 久久超级碰视频 | 97国产视频 | 国产精品永久久久久久久www | 国产精品美女久久久久久网站 | 欧美成人黄色片 | 天天se天天cao天天干 | 国产探花视频在线播放 | 久久久久久国产精品亚洲78 | 久色网| 中文字幕欧美日韩va免费视频 | 天天性天天草 | 久久a热6 | 俺要去色综合狠狠 | 麻豆国产精品视频 | 三级av免费 | 欧美日韩视频在线 | 美女视频黄频大全免费 | 久久久国产高清 | 日韩精品一区不卡 | 婷婷在线观看视频 | 国产一区免费看 | 91色欧美 | 99视频在线免费观看 | 亚洲a在线观看 | 亚洲精品女 | 亚洲激情 在线 | 成人黄色小说网 | 久久久久久久久久久网站 | 免费高清影视 | 91电影福利 | 天天干天天干天天射 | 探花视频网站 | 91精品国产自产91精品 | av在线网站大全 | 高清中文字幕av | 一级成人免费视频 | 五月激情久久 | 在线看av网址 | 国产一区二区三区免费视频 | 日韩高清免费在线 | 亚洲国产成人精品在线观看 | 日韩综合色 | 亚洲精品中文字幕视频 | 欧美少妇的秘密 | 波多野结衣日韩 | 欧美精品中文 | 超碰最新网址 | 国精产品一二三线999 | 天天爽人人爽夜夜爽 | 国产精品久久久一区二区 | 亚洲影音先锋 | 毛片久久久 | 毛片在线网 | 久久伊人八月婷婷综合激情 | 一级α片免费看 | 国产在线理论片 | 手机色站 | 97精品国产 | 91夫妻自拍 | 日韩免费在线观看 | 久久夜色精品国产欧美一区麻豆 | 麻豆国产在线视频 | 日韩r级电影在线观看 | 日韩精品一区二区三区不卡 | 中文在线8资源库 | 91精品国自产在线观看欧美 | 97超碰精品 | 欧美色综合天天久久综合精品 | 中文字幕免费观看全部电影 | 国内精品久久久久久久97牛牛 | 狠狠躁18三区二区一区ai明星 | 又长又大又黑又粗欧美 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 亚洲欧洲美洲av | 国产永久网站 | 天天操天天干天天操天天干 | 黄av免费在线观看 | 麻豆观看 | 福利网在线 | 亚洲在线免费视频 | 天天射天天干天天操 | 亚洲春色成人 | 9ⅰ精品久久久久久久久中文字幕 | 中文字幕在线观看视频网站 | 中文字幕中文字幕在线中文字幕三区 | 夜添久久精品亚洲国产精品 | 天天干天天射天天插 | 中文字幕人成不卡一区 | 久色网| 天干啦夜天干天干在线线 | 丁香网五月天 | 91在线视频网址 | www.狠狠操| 免费精品在线 | 久草观看| 久久久亚洲精华液 | 免费日韩电影 | 999视频网站 | 国产人成在线观看 | 美女网站免费福利视频 | 日韩综合视频在线观看 | 日韩精品亚洲专区在线观看 | 天天操天天操 | 久久综合狠狠 | 国产人免费人成免费视频 | 久久精品视频免费 | 91免费国产在线观看 | 日韩精品专区在线影院重磅 | 精品一区二三区 | 亚洲视频精品 | 成人黄色免费观看 | 米奇四色影视 | 日韩精品一区二区三区不卡 | 国产婷婷视频在线 | 天天色影院 | 中文字幕在线播放一区 | 久久午夜免费视频 | 美女免费电影 | 国产在线v| av在线电影免费观看 | 最新国产精品拍自在线播放 | av电影在线不卡 | 狠狠操操操 | 激情av在线播放 | 911亚洲精品第一 | 国产精品一区免费看8c0m | 国产精品久久久999 国产91九色视频 | 在线观看黄网站 | 又紧又大又爽精品一区二区 | 久久99爱视频 | 日韩av免费观看网站 | 丰满少妇久久久 | 亚洲国产福利视频 | 国产视频手机在线 | 国产精品成人av电影 | 麻豆一区在线观看 | 久久精品亚洲一区二区三区观看模式 | 91人人澡人人爽人人精品 | 激情久久久 | 免费一级片久久 | 91麻豆看国产在线紧急地址 | 丁香视频全集免费观看 | 2020天天干夜夜爽 | 国产精品久久久免费 | www.在线看片.com | 久久激情久久 | 91精品视频在线免费观看 | 中文在线字幕观看电影 | 超碰成人免费电影 | 韩国精品一区二区三区六区色诱 | 欧美a级片网站 | 亚洲丁香久久久 | 久草在线视频网站 | 国产午夜精品久久久久久久久久 | 午夜三级理论 | 亚洲黄色在线免费观看 | 最新精品国产 | 很黄很色很污的网站 | 国产精品成久久久久三级 | 亚洲午夜小视频 | 国产精品久久久久影院 | 97视频免费播放 | 日本3级在线观看 | www日日 | 999久久久久 | 亚洲最大在线视频 | 久久久久www | 丰满少妇麻豆av | av电影中文 | 日韩一二三 | 国产一区二区在线视频观看 | 区一区二区三区中文字幕 | 久久99精品久久久久久秒播蜜臀 | 色吊丝在线永久观看最新版本 | 免费男女羞羞的视频网站中文字幕 | 国产xxxx| 久久综合久久综合久久 | 最近中文字幕大全中文字幕免费 | 男女视频国产 | 夜色资源站国产www在线视频 | 99久久精品免费看国产一区二区三区 | 91精品一 | 四虎影视成人永久免费观看视频 | 亚洲高清视频在线观看 | 国内精品免费 | 香蕉视频91 | 国产91九色蝌蚪 | 五月婷综合网 | 99久久国产免费免费 | 久草免费新视频 | 91私密视频| 粉嫩av一区二区三区免费 | 免费男女羞羞的视频网站中文字幕 | 中文字幕在线视频网站 | 久久精品人 | 亚洲片在线 | 日本中文字幕电影在线免费观看 | 一区二区不卡 | 久久影院中文字幕 | 国产一级淫片在线观看 | 欧美日韩在线观看一区二区 | 免费黄色网址大全 | 午夜精品久久久久久久久久久 | 中文字幕黄色av | 99视频在线观看免费 | 欧美日韩不卡在线 | 很黄很色很污的网站 | 久久久www成人免费毛片麻豆 | 久草视频国产 | 成人在线一区二区 | 2024国产在线 | 免费看黄在线 | 久久99视频精品 | 国产精品一区二区在线观看 | 一区二区三区精品在线 | 久久久久久国产精品美女 | 中文字幕一区2区3区 | 国产成人99av超碰超爽 | japanese黑人亚洲人4k | 日韩在线第一区 | 中文av一区二区 | 一本一道久久a久久精品蜜桃 | 亚洲综合视频在线 | 日韩午夜精品福利 | 欧美日韩不卡一区二区 | 中文字幕电影一区 | 五月开心激情 | av综合 日韩| 亚洲精品乱码久久久久久蜜桃动漫 | 黄色录像av | av在线不卡观看 | 成人在线一区二区三区 | 在线亚洲观看 | 午夜精品一区二区三区在线 | 国产精品第72页 | www.色婷婷| 免费在线观看日韩欧美 | 国产免费成人av | 91大神dom调教在线观看 | 黄色成人av网址 | 亚洲精品国产综合99久久夜夜嗨 | 欧美日韩不卡在线 | 天天操夜夜操国产精品 | www日韩视频| 国内精品久久久久影院日本资源 | 97国产在线 | 久草在线免费新视频 | 99精品国产在热久久 | 视频二区在线 | 香蕉视频在线免费 | 美腿丝袜av | 婷婷色中文网 | 色婷婷激情四射 | 麻花豆传媒mv在线观看网站 | 四虎在线视频 | 日韩在线视频播放 | 国产大陆亚洲精品国产 | 超碰在线观看99 | 国产一级黄色电影 | 精品久久在线 | 久久久久美女 | 国产永久免费高清在线观看视频 | 91视频免费视频 | 日av免费| 黄色一及电影 | 久久久久女人精品毛片九一 | 色婷婷九月 | 国产高清 不卡 | 久久99精品久久久久蜜臀 | 高清在线一区二区 | 免费一级日韩欧美性大片 | 中文字幕在线观看第二页 | 欧美视频xxx | 在线观看黄网站 | 日本黄区免费视频观看 | 97av色 | av免费黄色 | 99久免费精品视频在线观看 | 人人看人人 | 成人毛片一区 | 久草视频播放 | 成片免费观看视频大全 | 亚洲精品美女免费 | 4438全国亚洲精品在线观看视频 | 免费a级大片 | 亚洲精品国产第一综合99久久 | 中文视频在线播放 | 国产亚洲精品久久 | 亚洲精品久久在线 | 日韩欧美精品一区二区三区经典 | 久久综合九色综合欧美就去吻 | 国产黄色高清 | 国产一二区视频 | www.天天干| 日本精品久久久久影院 | 成年人国产精品 | 美女搞黄国产视频网站 | 亚州精品一二三区 | 日韩欧美在线综合网 | 成人久久18免费网站图片 | 亚洲成人资源在线观看 | 日韩在线首页 | 久久精品久久精品久久39 | 亚洲高清激情 | 欧美一区二区伦理片 | 91视频在线免费下载 | 日本中文字幕网站 | 夜夜操天天摸 | 国内精品久久久久影院日本资源 | 午夜精品久久久久久久久久久久 | 在线亚洲观看 | 91视频在线观看下载 | 亚洲国产午夜精品 | 婷婷九九 | 亚洲黄色影院 | 久久久久女教师免费一区 | 欧美国产日韩激情 | 在线观看免费高清视频大全追剧 | 在线观看视频一区二区 | 国产精品嫩草55av | 国产精品一区二区免费看 | 日韩精品免费一线在线观看 | 国产精品久久久久久久久久久久 | 中文字幕亚洲欧美日韩2019 | 国产成人精品亚洲精品 | 久精品视频免费观看2 | 日本黄网站| 狠狠色丁香婷婷综合橹88 | 国产一区电影在线观看 | 97在线免费观看视频 | 欧美一区二区三区在线看 | 日韩黄色一级电影 | 另类老妇性bbwbbw高清 | 天天干天天操天天爱 | 国产在线观看免费 | 久久久免费看视频 | 91视频最新网址 | 国产精品不卡在线播放 | 激情综合中文娱乐网 | 深夜免费小视频 | 日韩美女免费线视频 | 国产一级片一区二区三区 | 麻豆视频免费在线观看 | 精品久久久久久久久久岛国gif | av电影中文字幕在线观看 | 97国产情侣爱久久免费观看 | 在线免费国产 | 国产va在线观看免费 | 欧美一级片 | 免费在线播放 | 国产一区二区不卡视频 | 在线婷婷 | 免费在线观看黄色网 | 久久97视频| 日韩国产高清在线 | 国产精品九九视频 | 国产伦理久久 | 伊人五月在线 | 性日韩欧美在线视频 | 99久久夜色精品国产亚洲 | 国产群p| 久久av免费观看 | 日韩高清三区 | 国产精品白浆 | 亚洲高清在线观看视频 | 成人av亚洲 | 日韩首页 | 久久伊99综合婷婷久久伊 | 一级性视频 | 91成人精品国产刺激国语对白 | 国产福利精品视频 | 久久久久久久久久久久影院 | 一区 在线观看 | 一二三四精品 | 六月婷操 | 国产精品免费久久久久久久久久中文 | 欧美日韩精品在线免费观看 | 视频在线精品 | 色婷婷导航 | 免费看黄在线看 | 最近免费中文视频 | 91女神的呻吟细腰翘臀美女 | 91手机在线看片 | 日韩中文字幕第一页 | 久久久综合九色合综国产精品 | 欧美国产亚洲精品久久久8v | 久久久久久久久久久免费av | 日韩色区 | 婷婷丁香激情综合 | 亚洲欧洲国产视频 | 久久久99久久 | 欧美成人猛片 | 国产高清视频在线 | 激情综合五月天 | 国产精品女人久久久 | 午夜视频二区 | 天天操比| 天天拍天天色 | 国产精品午夜久久 | 人人爱人人射 | 天天操天天草 | 精品国产1区二区 | 免费一级片观看 | 欧美日韩99| 成人久久综合 | 99精品热视频只有精品10 | 看全黄大色黄大片 | 日韩理论在线播放 | 日韩欧美在线免费观看 | 不卡av免费在线观看 | 四虎影视精品成人 | 国产+日韩欧美 | 国内精品99 | 色欧美综合 | 91夜夜夜 | 日韩网站一区二区 | 蜜臀久久99精品久久久久久网站 | 日本在线免费看 | 蜜臀精品久久久久久蜜臀 | 九九导航| 欧美一级片免费 | 久久久久久久国产精品 | 国产高清av在线播放 | 久久艹99| 久久不射网站 | 狠狠操综合 | 中文字幕91在线 | 久久精品视频网 | 日韩欧美观看 | 久久成| 亚洲精品一区二区三区新线路 | 91禁在线看 | 久草在线精品观看 | 五月婷婷精品 | 人人干网| 中文字幕精| 色播亚洲婷婷 | 999久久国产| 国产一区欧美日韩 | 欧美午夜寂寞影院 | 在线观看视频色 | 97色涩 | 91av在线视频免费观看 | 一区免费视频 | 日韩综合视频在线观看 | 国产电影黄色av | 久久久精品国产免费观看一区二区 | 免费视频xnxx com| 极品嫩模被强到高潮呻吟91 | 色综合www | 麻豆一精品传二传媒短视频 | 久久高清av | www五月婷婷 | 日日夜夜噜 | 99九九视频 | 人人干狠狠干 | 国产精品毛片久久久久久久 | 久久免费视频在线观看30 | 国产一区在线免费观看视频 | 日韩在线大片 | 97av精品| 97免费视频在线 | 欧美精品日韩 | 国产在线传媒 | 成人国产精品免费观看 | 2023av| 日日干天天射 | 欧美不卡视频在线 | www日韩欧美 | 日韩av电影中文字幕在线观看 | 国产一区二区三区网站 | 天天射一射 | 亚洲精品午夜视频 | 久久99热国产 | 日韩女同一区二区三区在线观看 | 欧美性大战久久久久 | 99视频在线观看视频 | 国产剧情一区二区 | 中文字幕在线不卡国产视频 | 日本一区二区三区免费观看 | 日韩中文字幕视频在线观看 | 免费视频在线观看网站 | 一区二区视频电影在线观看 | 国产日女人 | 看av免费| 天天综合天天综合 | 欧美巨乳波霸 | 全黄网站| 精品在线看 | 正在播放国产一区 | 亚洲激情校园春色 | 毛片a级片| 日韩电影久久久 | 国内久久久久 | 久久久美女 | 久久官网| 在线中文字幕视频 | 在线看毛片网站 | 韩日电影在线 | 中文国产字幕 | 欧美日韩国产一区二区在线观看 | 国产中文在线播放 | 91av社区 | 香蕉精品视频在线观看 | 美女视频久久黄 | 天天干天天干天天干天天干天天干天天干 | 日日操操 | 欧美性生活一级片 | 九九免费精品视频在线观看 | 午夜精品av | 超碰人人草 | www.五月天| 亚洲精品成人免费 | 免费亚洲成人 | 欧美精品三级在线观看 | 69精品在线 | 亚洲天堂首页 | 成人久久久久久久久 | 亚洲成av人片 | 欧美综合干 | 福利精品在线 | 欧美色久 | 免费三级网 | 就操操久久 | 五月婷婷六月综合 | 国产精品久久久久影院 | 在线免费av网 | 美女视频黄色免费 | 91精品在线视频 | 97国产精品一区二区 | 黄色网在线播放 | 91在线一区二区 | 国产一区二区三区免费在线观看 | 日韩久久久 | 免费在线一区二区 | 婷婷开心久久网 | 天堂资源在线观看视频 | 中文区中文字幕免费看 | 97国产小视频 | 99精品国产高清在线观看 | 国内精品久久久久 | 久草在线高清 | 国产福利资源 | 91精品国产自产在线观看 | 亚洲成人黄色网址 | 国产a级免费 | 日韩午夜av| 亚洲aⅴ乱码精品成人区 | 日韩视频www | 日本午夜免费福利视频 | 99视频精品在线 | 久久久久久中文字幕 | 欧美国产大片 |