亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Android識別預裝的第三方App方法實例

2019-10-21 21:26:45
字體:
來源:轉載
供稿:網友

前言

新買一臺手機,里面會有很多App,有的屬于系統App,不可卸載,有的屬于第三方App,廠商會預裝一些常用的或者給了他們廣告費的App,這些是可以卸載的。

如果要詳細劃分,系統App還可根據其路徑不同進一步劃分(如/system/app、/system/priv-app、/vendor/app等)。但對于開發者來說,手機上安裝的App只分為2類:系統App和用戶App,可以根據系統API區分,這里就不詳細說了,簡單而言存在ApplicationInfo.FLAG_SYSTEM或ApplicationInfo.FLAG_UPDATED_SYSTEM_APP flag的即為系統App,否則為用戶App。

但是,利用這個方法那些預裝的App也會歸到用戶App中,那么有沒有辦法知道用戶App中哪些是預裝的哪些是用戶手動安裝的呢?

在這里分享一種方法:App的安裝時間是整秒的為預裝的第三方App。

如果不關心為什么能用這個奇怪方法來區分預裝App的話,就可以關閉這篇文章了。

之前我也一直不清楚為什么可以用這種方法,當時我猜是因為手機第一次啟動的時候時間是不準確的,會是某某年1月1日,然后因為啟動時會掃描各個App目錄然后安裝App,因此被打上這樣的安裝時間。但這種解釋是說不通的,即便真是這樣,那安裝時間也不應該是整秒的。因此我決定好好找一下原因,以下是我求證的歷程。

背景知識

首先介紹一些背景知識。

App的安裝時間可以通過獲取PackageInfo得到,其firstInstallTime屬性即安裝時間。

/data/system/packages.xml保存了手機上安裝的App的信息,其中App的安裝時間就保存在這里。我在下面截取了2個示例。

<package name="com.tencent.mm" codePath="/data/app/com.tencent.mm-TSn6yG4fF7A_EaxE5OtrHQ==" nativeLibraryPath="/data/app/com.tencent.mm-TSn6yG4fF7A_EaxE5OtrHQ==/lib" primaryCpuAbi="armeabi" publicFlags="945307204" privateFlags="0" ft="167702c7508" it="1676feab448" ut="167702c8a57" version="1360" userId="10118">...</package><package name="com.android.providers.downloads" codePath="/system/priv-app/DownloadProvider" nativeLibraryPath="/system/priv-app/DownloadProvider/lib" publicFlags="944258629" privateFlags="8" ft="11e8dc5d800" it="11e8dc5d800" ut="11e8dc5d800" version="28" sharedUserId="10006" isOrphaned="true">...</package>

其中it的值便是安裝時間,這里是用十六進制保存的,上面這2個App的安裝時間換算成十進制分別是1543770911816和1230739200000,對應的北京時間即2018-12-03 01:15:11和2009-01-01 00:00:00。 【嗯…想不到我12月3號1點多還沒睡,還安裝了個微信……】

系統啟動時,PackageManagerService由SystemServer啟動,PackageManagerService會掃描/data/app、/system/app、/system/priv-app、/vendor/app等等目錄,可以理解為會把這些目錄中的Apk安裝一遍,PackageManagerService會結合上面提到的packages.xml把各個App解析成PackageParser.Package對象。

思路

根據上面的知識,我們可以知道,如果packages.xml已經有了某個App的信息,那么這個App的安裝時間肯定就是packages.xml中記錄的時間。第一次啟動手機時packages.xml文件還不存在,或者新安裝一個App時,packages.xml中還沒有這個App的記錄,也就是說,確認這個packages.xml中的firstInstallTime(即it)是如果生成的便是問題的關鍵。

以下基于7.0.0_r1版本代碼。

通過搜索PackageManagerService,在scanPackageDirtyLI方法中有這么一段代碼:

// Take care of first install / last update times.if (currentTime != 0) { if (pkgSetting.firstInstallTime == 0) { pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime; } else if ((scanFlags&SCAN_UPDATE_TIME) != 0) { pkgSetting.lastUpdateTime = currentTime; }} else if (pkgSetting.firstInstallTime == 0) { // We need *something*. Take time time stamp of the file. pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;} else if ((policyFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { if (scanFileTime != pkgSetting.timeStamp) { // A package on the system image has changed; consider this // to be an update. pkgSetting.lastUpdateTime = scanFileTime; }}

其中,currentTime是scanPackageDirtyLI方法的一個參數。pkgSetting是從packages.xml中讀取到的該App的信息(PackageSetting對象),如果packages.xml中不存在這個App的信息,會根據從Apk中解析到的信息創建一個PackageSetting。scanFileTime是Apk文件的最后修改時間。
可以看到存在這么幾種情況:

  • 傳入的currentTime不為0,從packages.xml中讀取到的firstInstallTime為0。這種情況會將firstInstallTime和lastUpdateTime均設置為傳入的currentTime的值。
  • 傳入的currentTime不為0,傳入的scanFlags設置了SCAN_UPDATE_TIME。這種情況會將lastUpdateTime設置為傳入的currentTime的值。
  • 傳入的currentTime為0,從packages.xml中讀取到的firstInstallTime為0。這種情況會將firstInstallTime和lastUpdateTime均設置為Apk的最后修改時間。
  • 傳入的currentTime為0,從packages.xml中讀取到的firstInstallTime不為0,傳入的policyFlags設置了PackageParser.PARSE_IS_SYSTEM_DIR,scanFileTime與packages.xml中讀取到的timeStamp(packages.xml中package標簽的ft)不相同。這種情況會將lastUpdateTime設置為Apk的最后修改時間。

對應到我們真實使用手機的場景,上面4種情況分別對應以下幾種場景:

  • 第一種情況:對應新安裝App。currentTime為當前的時間戳,會將這個新安裝的App的firstInstallTime和lastUpdateTime設置為當前時間戳。
  • 第二種情況:對應更新App。currentTime為當前的時間戳,會將lastUpdateTime設置為當前時間戳,firstInstallTime保持不變。
  • 第三種情況:手機啟動時PackageManagerService掃描各個目錄時發現了packages.xml中不存在的App(第一次啟動時所有App都不在packages.xml中)。
  • 第四種情況:系統更新等操作更新了系統分區的App,導致其文件的最后修改時間和記錄的不一致了,會被認為是更新。

我們可以大膽猜測,第一次啟動手機時會走第三種情況,因此系統App和預裝App的安裝時間是文件的最后修改時間,而這些文件的最后修改時間都是整秒的。

如何驗證?

我們先看看上面那個com.android.providers.downloads的Apk文件的最后修改時間。

# stat DownloadProvider.apk File: `DownloadProvider.apk' Size: 504712	 Blocks: 992	 IO Blocks: 512	regular fileDevice: 10305h/66309d	 Inode: 1308	 Links: 1Access: (644/-rw-r--r--)	Uid: ( 0/ root)	Gid: ( 0/ root)Access: 2009-01-01 00:00:00.000000000Modify: 2009-01-01 00:00:00.000000000Change: 2009-01-01 00:00:00.000000000

時間與packages.xml中保存的時間一致,確實是把文件的最后修改時間作為了安裝時間。那么還有一個問題需要確認,傳入的currentTime是0嗎?

我們追溯調用鏈,會在PackageManagerService的構造函數中看到掃描各個目錄的方法。調用scanDirTracedLI方法傳入的最后一個參數0即scanPackageDirtyLI方法中的currentTime。感興趣的還可以仔細看看PackageManagerService到底掃描了哪些目錄。

File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);scanDirTracedLI(vendorOverlayDir, mDefParseFlags  | PackageParser.PARSE_IS_SYSTEM  | PackageParser.PARSE_IS_SYSTEM_DIR  | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);// Find base frameworks (resource packages without code).scanDirTracedLI(frameworkDir, mDefParseFlags  | PackageParser.PARSE_IS_SYSTEM  | PackageParser.PARSE_IS_SYSTEM_DIR  | PackageParser.PARSE_IS_PRIVILEGED,  scanFlags | SCAN_NO_DEX, 0);// Collected privileged system packages.final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");scanDirTracedLI(privilegedAppDir, mDefParseFlags  | PackageParser.PARSE_IS_SYSTEM  | PackageParser.PARSE_IS_SYSTEM_DIR  | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);// Collect ordinary system packages.final File systemAppDir = new File(Environment.getRootDirectory(), "app");scanDirTracedLI(systemAppDir, mDefParseFlags  | PackageParser.PARSE_IS_SYSTEM  | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);// Collect all vendor packages.File vendorAppDir = new File("/vendor/app");try { vendorAppDir = vendorAppDir.getCanonicalFile();} catch (IOException e) { // failed to look up canonical path, continue with original one}scanDirTracedLI(vendorAppDir, mDefParseFlags  | PackageParser.PARSE_IS_SYSTEM  | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);// Collect all OEM packages.final File oemAppDir = new File(Environment.getOemDirectory(), "app");scanDirTracedLI(oemAppDir, mDefParseFlags  | PackageParser.PARSE_IS_SYSTEM  | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);...scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags  | PackageParser.PARSE_FORWARD_LOCK,  scanFlags | SCAN_REQUIRE_KNOWN, 0);

如果感興趣,你可以去跟一下安裝App和更新App的代碼,看傳入的currentTime是不是當前的時間戳。

到此,我們已經證明了第一次啟動手機時,系統會把文件的最后修改時間當成系統App和預裝App的安裝時間,而這個時間一般是類似于上面那樣2009-01-01 00:00:00.000000000的整秒的時間(至于為什么是這樣,那就是另一個問題了),而我們自己安裝App時幾乎不可能在一個整秒的時間安裝,所有我們可以用安裝時間是否為整秒來區分手機預裝的App和用戶手動安裝的App

至于區分預裝App和用戶手動安裝的App有什么用?請發揮你的想象,比如說,一個用戶的手機上只有你家一個手動安裝的App或者少數幾個App,那么他是想干什么好事呢?

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美黄色片免费观看| 亚洲国产精品人久久电影| 国产69精品久久久久9999| 久久久国产91| 日韩电影第一页| 欧美性极品少妇精品网站| 亚洲黄色av网站| 亚洲色在线视频| 福利一区福利二区微拍刺激| 欧美国产欧美亚洲国产日韩mv天天看完整| 精品国产精品自拍| 国产拍精品一二三| 欧美丰满少妇xxxxx| 亚洲美腿欧美激情另类| 国产一区二区成人| 91国产一区在线| 国产一区二区欧美日韩| 久久久视频免费观看| 在线观看久久av| 色妞色视频一区二区三区四区| 国产亚洲美女精品久久久| 韩剧1988在线观看免费完整版| 毛片精品免费在线观看| 亚洲另类欧美自拍| 国产精品一区二区久久国产| 欧美日韩国产二区| xxav国产精品美女主播| 欧美性色视频在线| 亚洲第一区中文字幕| 欧美激情乱人伦一区| 人人爽久久涩噜噜噜网站| 综合国产在线观看| 在线国产精品播放| 国产91露脸中文字幕在线| 中文字幕在线视频日韩| 欧美国产在线电影| 97精品视频在线| 亚洲最大成人网色| 午夜精品三级视频福利| 日韩欧亚中文在线| 久久精品久久久久电影| 欧美乱大交做爰xxxⅹ性3| 欧美日本在线视频中文字字幕| 日韩av不卡在线| 国产精品 欧美在线| 日韩激情片免费| 91日本在线视频| 日韩在线视频观看| 国产欧美在线看| 97成人在线视频| 992tv成人免费影院| 国产精品成人一区二区三区吃奶| 欧美精品videos另类日本| 久久国产精品久久久久| 色多多国产成人永久免费网站| 国产日韩亚洲欧美| 成人久久久久久| 午夜精品一区二区三区在线视频| 一区二区三区美女xx视频| 亚洲va欧美va在线观看| 精品国内产的精品视频在线观看| 久久精品国产欧美亚洲人人爽| www.99久久热国产日韩欧美.com| 亚洲自拍偷拍色图| 亚洲精品国产免费| 日韩最新在线视频| 日本午夜在线亚洲.国产| 国产精品 欧美在线| 亚洲jizzjizz日本少妇| 麻豆乱码国产一区二区三区| 91精品国产乱码久久久久久蜜臀| 亚洲人成网站999久久久综合| 自拍亚洲一区欧美另类| 在线精品视频视频中文字幕| 色综合老司机第九色激情| 福利一区福利二区微拍刺激| 久久亚洲综合国产精品99麻豆精品福利| 亚洲风情亚aⅴ在线发布| 久久深夜福利免费观看| 色偷偷偷亚洲综合网另类| 欧美肥老妇视频| 欧美人与性动交a欧美精品| 久久久久亚洲精品成人网小说| 久久久久久久久91| 欧美激情亚洲另类| 亚洲国内精品在线| 国产精品va在线播放我和闺蜜| 日韩国产欧美区| 欧美专区第一页| 国产女精品视频网站免费| 成人免费视频97| 久久久久久美女| 欧美成人性色生活仑片| 97精品伊人久久久大香线蕉| 亚洲男人的天堂在线播放| 日韩av三级在线观看| 亚洲欧洲黄色网| 北条麻妃在线一区二区| 亚洲精品视频免费在线观看| 91色视频在线导航| 亚洲激情在线视频| 中文字幕久热精品在线视频| 一区二区三区高清国产| 中文字幕久久久av一区| 亚洲第一中文字幕| 久久艳片www.17c.com| 久久久免费高清电视剧观看| 91国产美女在线观看| 中文字幕不卡av| 亚洲精品国产精品久久清纯直播| 亚洲美女激情视频| 一区二区三区四区视频| 国产精品视频专区| 中文字幕日韩av| 久久久久久久999精品视频| 清纯唯美亚洲综合| 成人a在线视频| 亚洲美女免费精品视频在线观看| 欧美猛少妇色xxxxx| 国产美女久久久| 国产精品久久久久久久久粉嫩av| 亚洲精品久久久久国产| yw.139尤物在线精品视频| 亚洲xxxxx电影| 亚洲永久免费观看| 亚洲自拍偷拍区| 国产精品青草久久久久福利99| 亚洲欧洲激情在线| 欧美亚洲国产日本| 97久久伊人激情网| 日韩免费观看高清| 日韩av在线不卡| 日韩精品一区二区视频| 欧美日韩一区二区在线播放| 欧洲日本亚洲国产区| 国产精品久久久久久久久久新婚| 国产精品视频999| 欧美一区二区三区图| 中国日韩欧美久久久久久久久| 国产91在线高潮白浆在线观看| 97超级碰碰碰久久久| 海角国产乱辈乱精品视频| 精品网站999www| 日本成人在线视频网址| 久久久综合免费视频| 日韩电影免费观看在线| 国产精品黄色影片导航在线观看| 国产精选久久久久久| 国产成人一区二区| 欧美巨猛xxxx猛交黑人97人| 成人av资源在线播放| 亚洲天堂av在线免费观看| 久久亚洲精品中文字幕冲田杏梨| 欧洲中文字幕国产精品| 亚洲剧情一区二区| 中文字幕成人精品久久不卡| 精品久久久久国产| 欧美午夜女人视频在线| 欧美在线视频一区二区| 国产一区二区免费| 亚洲福利视频在线| 91免费国产网站| 欧美日韩午夜激情| 亚洲国产欧美日韩精品|