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

289M→259M得物包體積治理實踐

開發 前端
經過了深度的治理以及組件編碼整合,期間cocoapods的改造與ruby原理的學習得益與Cat的請教,并得到各個iOS開發伙伴的無條件支持,同時將整個構建打包流程做了重構,以滿足組件編碼,經過多個版本的治理,得物的包大小在業務代碼迭代有增量的前提下,從289.3M降低至259.3M。

一、前言

iOS應用的包體積大小是衡量得物性能的重要指標,過大包體積會降低用戶對應用的下載意愿,還會增加用戶的下載等待時間以及用戶手機的存儲空間,本文重點介紹在包體積治理中的新思路以及原理與實踐。

二、原理介紹

Macho產物測試

我們拿測試工程單獨依賴一個組件,比如DemoModule,進行編譯MarchO得出整合前的大小:58929120Byte。同時為了方便分析,我們也導出Linkmap.txt文件。

Linkmap文件中記錄MachO文件中每個符號所占用的體積大小,因此通過分析Linkmap可以分析MachO具體符號占用變化,由于Linmap介紹不是本文重點,不多做贅述,更多詳情可參考網上文章https://juejin.cn/post/6844904168096792583。

隨后將組件工程中的文件編碼整合10~20個,得出整合后MachO的大小:58894688Byte。(下圖為編碼前和編碼后的MarchO占用磁盤大小)

圖片圖片

圖片圖片

LinkMap分析

整合后的文件變小了34K,我們繼續分析產物導出的Linkmap,具體查看是哪里變小了。

  • 通過對比Linkmap.txt發現:Text段減小10.6K、en_frame段減小了2K。

Linkmap.txt文件第一列展示的是符號的起始地址,第二列展示的是大小,16進制,將16進制轉換為10進制,即是大小。相減得出變化大小。

__text段存儲的機器編譯后的代碼。

en_frame存儲了函數調用入口幀信息。具體查看https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html。

Linkmap符號變化Linkmap符號變化

繼續解析Linkmap每個組件的變化,我們發現,DemoModule組件減小15K、連接器自動生成符號的變化減小2K。

圖片圖片

左圖為組建變化,右圖為鏈接符號變化左圖為組建變化,右圖為鏈接符號變化

通過對Linkmap的分析,確實存儲代碼段和函數入口幀信息減小使得編譯后的.o文件變小了,那么.o文件編碼整合為DemoModule.a文件也隨之變小了,那么到底是哪塊代碼變小了呢?我們繼續往下分析。

Mach-o代碼內容分析

Mach-o代碼內容分析

通過上面Linkmap的分析,我們知道了是代碼段以及函數調用符號占用的體積變小了,我們通過objcdump將MarchO符號進行導出。

objdump --macho -d  --start-address=0x10025FDD0 --stop-address=0x100257668  ~/Desktop/IPATestProj > ~/Desktop/result.txt
objdump --macho -d  --start-address=0x10025FDD0 --stop-address=0x100257668  ~/Desktop/IPATestProj-after > ~/Desktop/result-after.txt

對比發現

  1. 針對s13DemoModule0A29TSearchHotRecommendDemoModuleCACycfC優化了28Byte。
  2. allocWithZone以及objc的init方法。調用了DemoModule0A21FollowBrandDemoModuleCACycfC, DemoModule0A21FollowBrandDemoModuleCACycfC 調用了s13DemoModule0A17PaySendDemoModuleCACycfC,s13DemoModule0A17PaySendDemoModuleCACycfC里實現了alloc with zone和init方法。也就是說編譯器優化了經過編碼的alloc with zone方法,只會有一個alloc with zone 的實現。
  3. 針對s13DemoModule0A29TSearchHotRecommendDemoModuleCMr
  1. DemoModule.ExampleModule.__deallocating_deinit優化了32Byte
  1. 優化了meta的deinit與尋找metaclass的過程。s13DemoModule0A29DemoModuleCMa調用了s13DemoModule0A31tDemoModuleCMaTm - ,而 和SearchDemoModule同時繼承了CustomRequestDemoModule。

Alloc with zone前后對比

  • 整合編碼之前的逆向機器碼
_$s13DemoModule0A29TSearchHotRecommendDemoModuleCACycfC:
1002fe8c8:        fd 7b bf a9        stp        x29, x30, [sp, #-16]!
1002fe8cc:        fd 03 00 91        mov        x29, sp
1002fe8d0:        e0 03 14 aa        mov        x0, x20
1002fe8d4:        3d 2a 20 94        bl        0x100b091c8 ; symbol stub for: _objc_allocWithZone
1002fe8d8:        28 64 00 b0        adrp        x8, 3205 ; 0x100f83000
1002fe8dc:        01 79 44 f9        ldr        x1, [x8, #2288] ; Objc selector ref: init
1002fe8e0:        fd 7b c1 a8        ldp        x29, x30, [sp], #16
1002fe8e4:        7b 2a 20 14        b        0x100b092d0 ; Objc message: -[x0 init]
_$s13DemoModule0A29TSearchHotRecommendDemoModuleCACycfc
  • 整合編碼之后的逆向機器碼
1002577a0:        b2 ff ff 97        bl        _$s13DemoModule0A29TSearchHotRecommendDemoModuleCACycfc
1002577a4:        fd 7b 41 a9        ldp        x29, x30, [sp, #16]
1002577a8:        f4 4f c2 a8        ldp        x20, x19, [sp], #32
1002577ac:        c0 03 5f d6        ret
_$s13DemoModule0A29TSearchHotRecommendDemoModuleCfD:
1002577b0:        60 fe ff 10        adr        x0, #-52
1002577b4:        1f 20 03 d5        nop
1002577b8:        f2 fd ff 17        b        _$s13DemoModule0A31IdentComTrendDelLightDemoModuleCfDTm
_$s13DemoModule0A26TMeasureRecordAiUpdateSkinCACycfc:
  • Deinit前后對比-整合編碼之前
_$s13DemoModule0A29TSearchHotRecommendDemoModuleCMa:
1002fe9fc:        fd 7b bf a9        stp        x29, x30, [sp, #-16]!
1002fea00:        e8 03 00 aa        mov        x8, x0
1002fea04:        89 71 00 b0        adrp        x9, 3633 ; 0x10112f000
1002fea08:        20 7d 40 f9        ldr        x0, [x9, #248]
1002fea0c:        80 00 00 b4        cbz        x0, 0x1002fea1c
1002fea10:        01 00 80 d2        mov        x1, #0
1002fea14:        fd 7b c1 a8        ldp        x29, x30, [sp], #16
1002fea18:        c0 03 5f d6        ret
1002fea1c:        41 4c 00 90        adrp        x1, 2440 ; 0x100c86000
1002fea20:        21 80 24 91        add        x1, x1, #2336
1002fea24:        e0 03 08 aa        mov        x0, x8
1002fea28:        f7 2c 20 94        bl        0x100b09e04 ; symbol stub for: _swift_getSingletonMetadata
1002fea2c:        fd 7b c1 a8        ldp        x29, x30, [sp], #16
1002fea30:        c0 03 5f d6        ret
  • Deinit前后對比-整合編碼之后
0x10025777C        0x00000014        [583] _$s13DemoModule0A29TSearchHotRecommendDemoModuleCMa

由此可以得出結論。

  1. 編譯器針對不同的Class,經過編碼整合后,編譯時會觸發編譯優化,alloc with zone、deinit尋找metaclass方法。將文件編碼后整合會優化為一個。
  2. 同時相關的尋址和寄存器的addr,以及mov、內存地址的存儲已隨之刪除,具體對比結果可以看上面的產物對比。

三、落地實踐

經過上文的原理探究,整合一個組件有34K的收益,得物全工程是一個由1100+組件組成的Swift工程,那么我們基于組件的維度,將1100+組件做整合,那么就能拿到收益了,為了做到文件編碼整合,拿到收益,我們需要在穩定性的基礎上做到如下的目標。

  1. 需要滿足線上包、灰度包、測試包等所有CI流程出的包都是文件編碼整合后的包,并且需要保證相同的版本,文件編碼整合的一致性。

得物工程的組件化CI是使用Cocoapods來實現的,因此需要改造Cocoapods 的download流程,將文件編碼整合嵌入到所有的發版與打包的CI中。

為了滿足大家的正常使用,需要為pod定制命令,比如--megre-file --clean-sanbox,正常開發默認命令不生效,為打包機等CI任務配置命令,做到開發無感知,發版無縫整合。

  1. 需要判斷整個工程盤點出可能存在的風險點,并在整合前做改造,盤點出主要的改造點:
  2. 項目中存在同名的public或者open聲明的extension方法,之前存在于不同的文件編碼中,不會造成編譯報錯,經過編碼后之后會出現大量的編譯報錯,整合后通過編譯器去識別項目中同名的方法,在改造發版,每次改造編譯源碼都需要大量的時間,這顯然是不現實的,因此我們需要通過indexstore-db與 SwiftSytax將項目中所有的同名extension方法做識別統一改造,并一次性的編譯

  3. 項目中存在已#fileID、#file、#line方法與業務耦合,做調用位置判斷,由于文件編碼整合行號與,打包時的文件名都發生的變化,因此我們也需要通過SwiftSytax將所有方法導出,并做甄別改造。

  4. 需要分節奏,分版本,做好充分的灰度測試,灰度上線逐步拿到收益。

  5. 為了做到組件分版本灰度,需要為cocoapod bin pod命令增加版本的概念,為每個上線的組件配置好版本號,滿足配置的組件在執行整合,不滿足的組件走原有download流程。

如何滿足上述3項目標,下面為大家逐一介紹。

Cocoapods原理與實踐

介紹流程:當我們執行pod install時,會在你的電腦發生如下步驟。

1. 執行pod install時會進入到本機電腦的/usr/local/bin/pod我們發現是一個快捷方式。

圖片圖片

2. 右鍵點擊顯示原項目,我們就進入到了真正的執行指令的入口目錄。

圖片圖片

由于筆者的pod是使用homebrew裝的,因此pod可執行文件在homebrew的安裝目錄: /opt/homebrew/Cellar,這個pod文件本質是個bash sh文件,咱們將文件已編輯器打開有如下的內容。

GEM_HOME="/opt/homebrew/Cellar/ruby環境根目錄" exec "/opt/homebrew/Cellar/真實的cocoapods目錄/bin/pod"  "$@"

繼續打開后面的執行文件,發現這個pod文件就是cocoapods安裝文件下的pod,pod是一個ruby文件,也就是cocoapods最終的命令入口,內容如下:

#!/usr/bin/env ruby
require 'rubygems'
if Gem.respond_to?(:activate_bin_path)
load Gem.activate_bin_path('cocoapods', 'pod', version)
else
gem "cocoapods", version
load Gem.bin_path("cocoapods", "pod", version)
end

3. 隨后就進入到了cocoapods的cocoapods/cocoapods.rb,cocoapods.rb引入了 核心類,比如:

Xcodeproj::PlainInformative.send(:include, CLAide::InformativeError)
    autoload :Command,                   'cocoapods/command' # 命令行入口
    autoload :ExternalSources,           'cocoapods/external_sources' # git 依賴,本地依賴處理類
    autoload :Installer,                 'cocoapods/installer' # pod install核心 類

cocoapods/command是一個基類,每個命令pod install、pod update、pod repo add都會有相應command重寫。可查看下面的截圖:

圖片圖片

4. 我們單純拿pod install看文件里的內容。就知道我們如何給pod命令傳遞參數了。

  • 從文件內容可以看到class Install繼承了 Command,def initialize中定義需要傳遞的參數其中clean_install就是我們常用pod install --clean-install命令。
  • def run函數進入了install的流程,下面也為大家簡單注釋了每個函數的作用。
def initialize(argv)
        super
        @deployment = argv.flag?('deployment', false)
        @clean_install = argv.flag?('clean-install', false)
      end


      def run
        verify_podfile_exists! # 校驗 工程目錄Podfile 文件是否存在
        installer = installer_for_config # 根據config 生成 installer
        installer.repo_update = repo_update?(:default => false) # 配置是否需要更新索引庫
        installer.update = false # 由于是install 因此 update 是false
        installer.deployment = @deployment 
        installer.clean_install = @clean_install
        installer.install! # 進入真正的install 流程
      end

那installer.install里面做了什么呢?我們繼續往下看:

5.下面是installer.install的源碼,我們可以簡單將install分為以下步驟:

圖片圖片

# install 源代碼
def install!
  prepare
  resolve_dependencies # 依賴鏈分析
  download_dependencies # 
  validate_targets
  clean_sandbox
  if installation_options.skip_pods_project_generation?
    show_skip_pods_project_generation_message
    run_podfile_post_install_hooks
  else
    integrate
  end
  write_lockfiles
  perform_post_install_actions
end

  • resolve_sependencies會更新索引庫,得到pods target對應的數據,得到aggregate target對應的數組,并提前加載git依賴與本地依賴的組件。為下載pod依賴做環境準備。

1. 為了能將:git、:branch、:commit依賴與本地:path依賴做代碼編碼并整合,我們需要再resolve_dependencies中加載git依賴與本地依賴階段時做hook,滿足本地依賴與git依賴組件集成時做代碼編碼整合。

2. 為了能對正常pod"Example"組件做整合,我們需要再download_dependencies中對組件做整合。具體實現整合與定制參數傳入,我們繼續往下看。

Pod命令改造:引入pod update --transform-local --transform-file。

1. 上文我們了解了,每個command都有一個命令類,為了不污染cocoapods的源碼,使得能正常隨著cocoapods更新進行升級,我們模仿cocoapods設計的想法,在cocoapods/cocoapods.rb核心類引入hook/hook_option.rb,cocoapods.rb加入的內容如下:

# hook_file用于統一管理du_hook文件
# 判斷有沒有hook_file
if File.exist?(File.join(__dir__, 'cocoapods/du_hook/hook_file.rb'))
  require 'cocoapods/hook/hook_file'
end

2. 在hook_file中,Cat同學為cocoapods做了熱更新機制,同時引入了main_hook.rb、main_hook.rb中引入了得物為cocoapods做的魔改部分。代碼如下:

熱更機制簡單理解就是每次執行pod命令時會執行git操作,將魔改部分的倉庫代碼保持到最新,Cat這一巧妙的設計讓得物iOSer都能實時享受到cocoapods改造帶來的新功能。

require 'cocoapods/hook/cocoapods-hook/cocoapods_concurrent_hook' # 魔改的高并發下載
require 'cocoapods/hook/cocoapods-hook/cocoapods_option' # 為cocoapod 加入 命令參數的入口

3. 我們繼續往下看,在cocoapods_option.rb文件中。咱們模仿cocoapods的設計邏輯,對命令解析。如果有傳入--transform-file --transform-local 參數,那么就引入 cocoapods_transform_file.rb 文件,進入文件編碼整合的入口。

module Pod
  class Command
    module Options
      module Demo
        module Options
        def initialize(argv)
          # 每個電腦都有一個全局的環境變量,在執行命令的生命周期內是一直存在的,給環境變量傳入配置,不改動cocoapods的config源配置文件,不入侵cocoapods的源代碼。
          ENV['transform_FILE'] = '1' if @transform_file 
          ENV['ransform_LOCAL'] = '1' if @transform_local
          super
        end
      end
    end
  end
end

Ruby是一個運行時的動態語言,在required cocoapods_transform_file文件中,將指定的cocoapods函數進行重寫,就能實現HOOK的功能。

  1. 因此在cocoapods_transform_file.rb文件中覆蓋cocoapods/external_sources/path_source.rb 下class PathSource的fetch方法就能定制為本地依賴的組件、git依賴的組件的組件執行定制的整合能力
  2. 覆蓋cocoapods/downlod.rb下的Module Downloader self.download module類方法就能定制為pod"Example"的組件執行定制的整合。

具體的整合思路我們繼續往下看。

Pod組件編碼整合介紹

  • 我們為每個組件配置了整合的版本號,每次需要進行整合時會傳入版本號,默認是不整合,當一個組件進入download流程。會優先判斷組件配置的版本號是否滿足。
  • 如果不滿足那么不進行整合,正常執行常規的下載流程。
  • 如果滿足:

會繼續判斷是否在存在已經緩存好的文件夾,如果存在,直接將整合好的緩存文件Copy到Pods文件夾

Cococoapods的組件緩存目錄在~/Library/Caches/Cocoapods/Pods/Release/<版本號>-hash

我們為了能提高整合的效率為每個整合好的組件也進行緩存,這樣能明顯提高cocoapods的下載效率。命令規則會在原目錄下多一份~/Library/Caches/Cocoapods/Pods/Release/<版本號>-hash-setuped。

  • 如果不存在緩存文件,那么解析podspec,拿到待整合文件數組,執行整合,保存整合后的緩存,并將整合后的緩存Copy到Pods文件夾。

圖片圖片

本地依賴組件整合介紹

  • 當本地依賴組件進入fetch方法,判斷組件配置的版本號是否滿足,不滿足不執行整合。
  • 滿足則執行整合,并將整合的內容保存到新文件中,保存到pod target數組中以備后續cocoapods生成本地組件的pod targets。

圖片圖片

Native代碼整改

為什么要改造?

  • 針對所有文件做編碼并整合,會使得分散在不同文件中的同名方法名稱沖突,使得工程無法編譯成功,因此需要掃描出工程中所有的同名方法,并掃描出同名方法的上層調用。

如何改造?

  • 掃描工程中所有的方法可以借助swift-syntax或者SwiftLint自定義規則具體掃描代碼可參考如下。

SwiftLint中依賴了Swiftsytax,本質都是借助Swiftsyntax進行詞法分析,掃描出工程的所有extension同名函數,并進行改造。

override func visitPost(_ node: ExtensionDeclSyntax) {
            let functionList = _isFunctionDecl(node)
            guard !functionList.isEmpty else { return }
            for funcItem in functionList {
                // 如果是private function 那么不納入考慮范圍
                guard !_isPrivateFunction(funcItem) else { continue }
                // 如果不是public的extension,并且函數也不是public 那么這個函數就不是公開函數,也可以忽略
                if !isPublicExtension && !_isPublicFunction(node: funcItem) {
                    continue
                }
                violations.insert(ReasonedRuleViolation(position: funcItem.position, reason: funcItem.resolvedName(), severity: .warning), at: violations.count)
            }
        }
  • 掃描出同名方法后,使用indexstore-db將方法簽名傳入,通過掃描產物,可得出方法的上層調用,并進行統一改造,indexstore-db使用可參考如下

Indexstore-db是一個用于存儲和管理源代碼索引數據的開源工具。indexstore-db工具可以收集和存儲源代碼的元數據信息,包括符號、模塊依賴關系、引用關系等,以便在開發工具(如Xcode)中進行快速的代碼導航和搜索。它在構建大型代碼庫時尤其有用,可以提高代碼編輯、查找引用、代碼重構等操作的效率。

func testExtensionSymbol() throws {
        // indexstore-db 的動態加載庫
        let libIndexStore = try! IndexStoreLibrary(dylibPath: "/Applications/Xcode.app/xxx/libIndexStore.dylib")
        // 生成indexstore 實例
        let indexWait = try IndexStoreDB(storePath: "/Users/xxx/Library/Developer/Xcode/DerivedData/.../DataStore", databasePath: "/Users/xxx/Downloads/aaa", library: libIndexStore, waitUntilDoneInitializing: true)
        indexWait.pollForUnitChangesAndWait()
        // 假設我們需要掃描如下的文件
       let symbols = indexWait.symbols(inFilePath: "/Users/xxx/Project/String+Demo.swift")
      for symbol in symbols {
              // 假設我們需要掃描searchAtRange函數。
          guard symbol.name == "searchAtRange()" else { continue}
          let res = indexWait.occurrences(ofUSR: symbol.usr, roles: .reference)
          for x in res {
              debugPrint(x.relations.compactMap({ symbol in
                  return symbol.symbol.usr
              }))
          }
      }
  }

組件發版流程重構

為什么要改造?

  • 將cocoapods與同名方法改造完后,我們進行全工程源碼編譯是可以通過的,而且由于做了編碼整合,編譯時長也降低了5~8分鐘,但是當發布組件發布CI時發現,未整合的組件二進制與整合的源碼會出現link時符號不對齊的問題。

未整合的組件二進制符號是確定的,調用下游的符號簽名也是確定的,Swift有 fileprivate的函數定義,當函數由A文件經過編碼遷移到整合后的文件時,函數的簽名也會變化。因此會出現函數簽名符號不對齊。

如何改造?

  • 得物工程每個版本都有一個源碼索引庫和二進制索引庫,因此在組件發版時,我們需要再創建一個索引庫,編碼整合后的二進制索引庫,并重新建立一套編碼整合的二進制的CICD打包流程。具體流程可參考如下。

開發者開發時使用正常的二進制制作任務。發版與出包的打包機會使用整合二進制索引庫。這樣設計使得對日常開發無感知,而且能保證對外提測的任務都是整合后的包。

圖片圖片

整合符號表

  • 上述的改造解決了編譯和出包的問題,但編譯后的報錯工程師閱讀會比較困難,為了解決這個問題,引入了整合符號表,能根據符號表,反推出源工程的文件名以及行號,這就解決了編譯報錯閱讀難的問題。

圖片圖片

四、總結與收益

經過了深度的治理以及組件編碼整合,期間cocoapods的改造與ruby原理的學習得益與Cat的請教,并得到各個iOS開發伙伴的無條件支持,同時將整個構建打包流程做了重構,以滿足組件編碼,經過多個版本的治理,得物的包大小在業務代碼迭代有增量的前提下,從289.3M降低至259.3M。

圖片圖片

圖片圖片

下面列出每個階段治理做個小結。

責任編輯:武曉燕 來源: 得物技術
相關推薦

2023-07-19 22:17:21

Android資源優化

2025-03-13 06:48:22

2023-03-30 18:39:36

2025-11-11 01:55:00

2020-06-14 08:37:59

M2M物聯網IOT

2023-10-09 18:35:37

得物Redis架構

2018-03-08 05:58:20

網絡M2M物聯網

2021-12-09 12:04:48

云服務集成框架

2022-12-14 18:40:04

得物染色環境

2023-02-08 18:33:49

SRE探索業務

2023-11-27 18:38:57

得物商家測試

2014-04-18 11:22:10

華為物聯網新M2M模塊

2022-10-26 18:44:33

藍紙箱設計數據

2025-07-31 00:00:25

2023-08-09 20:43:32

2020-04-16 22:22:02

物聯網IOT萬物聯網

2021-06-01 11:11:26

物聯網互聯網IoT

2023-02-01 18:33:44

得物商家客服

2023-11-29 18:41:35

模型數據

2022-12-09 18:58:10

點贊
收藏

51CTO技術棧公眾號

久久国产生活片100| 国产精品一区二区日韩| 免费看黄色91| 久久天天躁狠狠躁夜夜躁| 男女视频在线观看网站| caoporn-草棚在线视频最| 久久久不卡网国产精品一区| 欧美性视频精品| 亚洲AV成人无码网站天堂久久| 国产一区二区三区| 日韩欧美国产一区二区| 在线成人性视频| 天天干天天做天天操| 视频精品一区二区| 精品国产一区av| 男人网站在线观看| 日韩精品免费观看视频| 亚洲图片欧美一区| 这里只有精品66| 午夜福利一区二区三区| 久久成人麻豆午夜电影| 日本一区二区不卡| 国产一级在线视频| 亚洲女同中文字幕| 国产午夜精品免费一区二区三区 | 久热这里有精品| 亚洲天堂日韩在线| 欧美成人aa大片| 五月花丁香婷婷| 精品欧美一区二区三区在线观看 | 北条麻妃一区二区三区| 国产精品黄色影片导航在线观看| 91 在线视频| 丝袜av一区| 精品国产免费视频| 在线视频观看一区二区| 成人黄色免费网站| 色域天天综合网| 精品视频免费在线播放| 国产美女av在线| 国产精品久99| 亚洲va韩国va欧美va精四季| av网页在线观看| 亚洲成人1区| 欧美在线观看一二区| 欧美一区二区三区爽大粗免费 | 国内精品一区二区三区| 免费网站观看www在线观| 久久久久久免费视频| 综合久久五月天| 在线观看亚洲大片短视频| 视频一区欧美| 一区二区三区精品99久久 | 亚洲精品97久久中文字幕无码 | 亚洲自拍偷拍视频| 国产精品女人久久久| 裸体一区二区三区| 成人国产在线视频| 97超碰人人草| 国产乱码精品一区二区三| 95av在线视频| 狠狠躁日日躁夜夜躁av| 99久免费精品视频在线观看| 精品在线观看一区二区| 青青草在线免费视频| 久久久亚洲欧洲日产国码αv| 欧美凹凸一区二区三区视频| 撸视在线观看免费视频| 中文一区二区在线观看| 黄瓜视频免费观看在线观看www| 免费观看在线午夜影视| 一区二区三区av电影| 日韩伦理在线免费观看| 亚洲精品成人图区| 欧美亚洲动漫另类| 五月天国产视频| 精品亚洲自拍| 国产亚洲精品va在线观看| 日本少妇aaa| 国产精品mm| 国产97在线播放| 国产麻豆免费视频| 99国产精品久久久久久久久久久| 欧美日韩另类丝袜其他| 免费黄网站在线| 精品久久久久久电影| 欧美黑人又粗又大又爽免费| 91精品国产一区二区在线观看| 欧美一区二区三区在线观看视频| 手机在线成人av| 日韩成人精品一区二区| 欧美激情视频给我| 这里只有精品免费视频| 国产精品18久久久久久久网站| 精品欧美一区二区精品久久| 在线视频二区| 无码av中文一区二区三区桃花岛| 能看的毛片网站| 亚洲2区在线| 国产亚洲精品久久| 日本少妇性高潮| 久久国产乱子精品免费女| 成人av播放| 尤物在线视频| 欧美日韩亚洲国产一区| 污污视频在线免费| 欧美伦理影院| 国产91精品高潮白浆喷水| 一级特黄色大片| 久久先锋资源网| 免费的av在线| 黄色精品视频| 精品亚洲一区二区三区| 青青草原在线免费观看| 奇米888四色在线精品| 狠狠色综合一区二区| 成人高清免费在线| 欧美性xxxxxx少妇| 最新在线黄色网址| 欧美午夜不卡| 亚洲综合小说区| 永久免费在线观看视频| 欧美性开放视频| 亚洲av无码一区东京热久久| 999精品色在线播放| 日韩免费av片在线观看| 日本高清视频www| 亚洲激情自拍视频| 亚洲精品久久久久久宅男| 一本色道久久综合亚洲精品酒店| 久久久久久有精品国产| 国产黄色一区二区| 亚洲免费电影在线| 夜夜夜夜夜夜操| 日韩毛片视频| 国产精品自拍偷拍| 岛国大片在线观看| 91精品福利视频| 亚洲第一香蕉网| 奶水喷射视频一区| 久久久久欧美| 亚洲精品国产精品国产| 精品中文视频在线| 亚洲欧美精品一区二区三区| 91美女福利视频| 波多野结衣家庭教师在线| 久久夜色电影| 欧美一级片一区| 五月婷婷六月色| 一区二区三区精品久久久| 在线观看免费av网址| 日韩免费在线| 成人免费视频a| 黄色网址在线免费| 欧美一区二区二区| 九九视频免费看| 东方欧美亚洲色图在线| 人人妻人人澡人人爽欧美一区| 亚洲成av人片在线观看www| 欧美精品少妇videofree| 亚洲av无码一区二区三区性色| 一区二区视频在线| 在线播放av网址| 亚洲高清不卡| 久久精品五月婷婷| free欧美| 日韩在线高清视频| 国产超碰人人模人人爽人人添| 亚洲免费成人av| 国产精品一区二区无码对白| 99成人在线| 欧美日韩精品不卡| 亚洲欧洲日韩精品在线| 欧美国产欧美亚洲国产日韩mv天天看完整| 成人免费一级视频| 91黄色免费版| 色老板免费视频| 从欧美一区二区三区| 国自产拍偷拍精品啪啪一区二区| 神马久久av| 成人激情视频网| 蜜臀av在线| 亚洲免费伊人电影在线观看av| 波多野结衣一区二区三区四区| 日韩一区在线播放| 2一3sex性hd| 免费看欧美女人艹b| 欧美在线观看视频免费| 国产亚洲电影| 99影视tv| 亚洲成人va| 午夜精品久久久久久久男人的天堂 | av电影网站在线观看| 久久er99热精品一区二区| 91午夜在线观看| 国内爆初菊对白视频| 亚洲大片精品永久免费| 在线看片中文字幕| 成人激情小说网站| 国模私拍视频在线观看| 亚洲视频www| 中文字幕在线中文| 欧美一二区在线观看| av在线亚洲男人的天堂| 99久久er| 久久久人成影片一区二区三区观看| 少妇人妻偷人精品一区二区| 欧美三级电影网| 成年人免费看毛片| 亚洲欧美日韩中文播放| 精品人妻一区二区三区日产乱码卜| 久久99精品视频| 农村妇女精品一二区| 欧美日韩日本国产亚洲在线| 香蕉久久夜色| 国产成人精品一区二区免费看京| 91入口在线观看| 农村妇女一区二区| 国产91色在线| 欧美少妇网站| 久久久久久久网站| 久操视频在线| 日韩在线一区二区三区免费视频| 香蕉久久一区二区三区| 日韩欧美国产一区在线观看| 在线播放一级片| 91福利视频网站| 色一情一乱一伦| 婷婷久久综合九色国产成人 | 国产日产欧美a一级在线| 伊人久久精品一区二区三区| 98精品在线视频| 99re6在线精品视频免费播放| 欧美成人免费va影院高清| 欧美日韩在线资源| xvideos国产精品| 在线免费av电影| 影音先锋日韩有码| av电影在线观看网址| 国产亚洲欧美日韩精品| 九色视频在线播放| 亚洲欧美日韩天堂| 成人18在线| 中文字幕日韩有码| 日本高清在线观看wwwww色| 色综合影院在线| www.欧美日本韩国| 另类专区欧美制服同性| 在线不卡日本v二区707| 欧美乱妇高清无乱码| 成人av免费| 欧美精品18videosex性欧美| 蜜乳av一区| 97视频在线观看成人| 日韩激情电影免费看| 欧美一区二粉嫩精品国产一线天| 无码小电影在线观看网站免费| 人体精品一二三区| 久久野战av| 国产主播在线一区| 国产999精品在线观看| 99www免费人成精品| 玖玖玖免费嫩草在线影院一区| 免费在线观看91| 青青草国产成人a∨下载安卓| 三年中文高清在线观看第6集| 欧美成人一品| 国产精品秘入口18禁麻豆免会员| 欧美一级片免费在线观看| 国产一区美女在线| 亚洲国产精品第一页| 99久久久久久| 亚洲天堂精品一区| 国产精品不卡在线观看| 91嫩草|国产丨精品入口| 亚洲国产精品影院| 尤物视频免费观看| 欧美一区二区免费观在线| 色婷婷av一区二区三区之红樱桃| 亚洲欧美日韩爽爽影院| а√天堂8资源在线官网| 97精品视频在线| 99久久精品一区二区成人| 97视频热人人精品| 国产一区二区三区四区五区传媒| 一区二区不卡在线| 亚洲欧美不卡| 无套内谢丰满少妇中文字幕| 91亚洲国产成人精品一区二区三| 一区二区三区在线播放视频| 亚洲第一福利视频在线| 国产成人av免费| 亚洲а∨天堂久久精品喷水| 网友自拍视频在线| 午夜精品久久久久久久99黑人| 欧美日韩破处视频| 久久精品国产一区二区三区日韩| 99久久激情| 欧美精品色婷婷五月综合| 激情图片小说一区| 久久久久亚洲av成人无码电影| 一区二区视频免费在线观看| 夜夜躁日日躁狠狠久久av| 亚洲精品一区二区三区四区高清| 91精彩视频在线观看| **欧美日韩vr在线| 欧美9999| 一个色的综合| 久久激情婷婷| 成人性生活免费看| 亚洲男人的天堂在线观看| 超碰在线97观看| 国产丝袜一区视频在线观看| 中文字幕伦理免费在线视频| 国产精品女人久久久久久| 日韩高清影视在线观看| 国产一线二线三线女| 国产精品影音先锋| 国产一区二区三区视频播放| 一本大道久久精品懂色aⅴ| 丰满肥臀噗嗤啊x99av| 欧美wwwxxxx| 欧美xxxx性| 亚洲欧美日韩精品在线| 三级欧美韩日大片在线看| 黄色在线观看av| 精品美女国产在线| 特级丰满少妇一级aaaa爱毛片| 欧美成人精品xxx| 97色婷婷成人综合在线观看| 亚洲欧洲国产精品久久| 日韩和欧美的一区| 日本少妇xxxxx| 欧美系列一区二区| av网在线观看| 91精品国产综合久久香蕉最新版 | 高清无码一区二区在线观看吞精| 老司机精品视频导航| 天堂资源在线视频| 欧美丝袜自拍制服另类| 成人免费在线观看| 国产精品第七十二页| 欧洲杯半决赛直播| 天天视频天天爽| 国产精品理论片在线观看| 伊人免费在线观看| 精品国偷自产在线视频| av在线精品| www插插插无码免费视频网站| 国产精品一区二区在线观看不卡 | 久久精品91| 日韩丰满少妇无码内射| 欧美性色黄大片手机版| 欧美成人性生活视频| 92国产精品久久久久首页| 欧美体内she精视频在线观看| 日本五十肥熟交尾| 狠狠躁夜夜躁久久躁别揉| 高清国产福利在线观看| 成人福利视频网| 欧美在线观看天堂一区二区三区| 亚洲天堂小视频| 亚洲成人免费在线观看| 无码国产精品一区二区色情男同| 日本久久久久久久久| 超碰成人久久| 古装做爰无遮挡三级聊斋艳谭| 亚洲一区二区三区视频在线 | 中文字幕久久久| 国产美女视频一区二区| 国产精品成人久久电影| 久久久五月婷婷| 国产精品高潮呻吟av| 久久理论片午夜琪琪电影网| 奇米色欧美一区二区三区| 日韩欧美国产片| 亚洲成人激情自拍| 在线观看免费黄视频| 国产日韩一区二区三区| 奇米色一区二区三区四区| 久久久久久久极品内射| 亚洲美女免费精品视频在线观看| 日韩第二十一页| 精品丰满人妻无套内射| 欧美极品aⅴ影院| 成人免费一级视频| 国产精品久久久久久一区二区| 亚洲图片在线| 亚洲av熟女国产一区二区性色| 日韩欧美你懂的| 欧美成a人片在线观看久| 黄色一级大片免费| 中文字幕不卡在线观看| 欧美 日韩 国产 成人 在线| 国产精品久久久久久久久久免费 | 55夜色66夜色国产精品视频| 国产国产精品| 国产手机在线观看| 精品国产乱码久久| www999久久|