国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

金川做網(wǎng)站公司網(wǎng)絡(luò)推廣代運(yùn)營(yíng)公司

金川做網(wǎng)站公司,網(wǎng)絡(luò)推廣代運(yùn)營(yíng)公司,安徽省交通運(yùn)輸廳施平,根河企業(yè)網(wǎng)站建設(shè)Android 系統(tǒng)源碼源碼-應(yīng)用安裝過(guò)程 Android 中應(yīng)用安裝的過(guò)程就是解析 AndroidManifest.xml 的過(guò)程,系統(tǒng)可以從 Manifest 中得到應(yīng)用程序的相關(guān)信息,比如 Activity、Service、Broadcast Receiver 和 ContentProvider 等。這些工作都是由 PackageManage…

Android 系統(tǒng)源碼源碼-應(yīng)用安裝過(guò)程

Android 中應(yīng)用安裝的過(guò)程就是解析 AndroidManifest.xml 的過(guò)程,系統(tǒng)可以從 Manifest 中得到應(yīng)用程序的相關(guān)信息,比如 Activity、Service、Broadcast Receiver 和 ContentProvider 等。這些工作都是由 PackageManageService 負(fù)責(zé)的,也就是所謂的 PMS. 它跟 AMS 一樣都是一種遠(yuǎn)程的服務(wù),并且都是在系統(tǒng)啟動(dòng) SystemServer 的時(shí)候啟動(dòng)的。下面我們通過(guò)源代碼來(lái)分析下這個(gè)過(guò)程。

1、啟動(dòng) PMS 的過(guò)程

系統(tǒng)在啟動(dòng) SystemServer 的過(guò)程會(huì)啟動(dòng) PMS,系統(tǒng)的啟動(dòng)過(guò)程可以參考下面這篇文章學(xué)習(xí),

Android 系統(tǒng)源碼-1:Android 系統(tǒng)啟動(dòng)流程源碼分析

在啟動(dòng) SystemServer 的時(shí)候會(huì)調(diào)用 startBootstrapServices() 方法啟動(dòng)引導(dǎo)服務(wù)。PMS 就是在這個(gè)方法中啟動(dòng)的,

    private void startBootstrapServices() {// ...mPackageManagerService = PackageManagerService.main(mSystemContext, installer,mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);mFirstBoot = mPackageManagerService.isFirstBoot();mPackageManager = mSystemContext.getPackageManager();// ...}

可以看出,系統(tǒng)是通過(guò)調(diào)用 PMS 的 main 方法來(lái)將其啟動(dòng)起來(lái)的。其 main 方法會(huì)先實(shí)例化一個(gè) PMS 對(duì)象,然后調(diào)用 ServiceManager 的靜態(tài)方法將其注冊(cè)到 ServiceManager 中進(jìn)行管理。

    public static PackageManagerService main(Context context, Installer installer,boolean factoryTest, boolean onlyCore) {PackageManagerServiceCompilerMapping.checkProperties();PackageManagerService m = new PackageManagerService(context, installer,factoryTest, onlyCore);m.enableSystemUserPackages();ServiceManager.addService("package", m);final PackageManagerNative pmn = m.new PackageManagerNative();ServiceManager.addService("package_native", pmn);return m;}

當(dāng)我們需要使用 PMS 解析 APK 的時(shí)候就會(huì)從 ServiceManager 中獲取。

在 PMS 的構(gòu)造方法中有許多工作要完成。一個(gè) APK 安裝的主要分成下面幾個(gè)步驟,

  1. 拷貝文件到指定的目錄:默認(rèn)情況下,用戶安裝的 APK 首先會(huì)被拷貝到 /data/app 目錄下,/data/app 目錄是用戶有權(quán)限訪問(wèn)的目錄,在安裝 APK 的時(shí)候會(huì)自動(dòng)選擇該目錄存放用戶安裝的文件,而系統(tǒng)的 APK 文件則被放到了 /system 分區(qū)下,包括 /system/app/system/vendor/app,以及 /system/priv-app 等等,該分區(qū)只有 ROOT 權(quán)限的用戶才能訪問(wèn),這也就是為什么在沒(méi)有 Root 手機(jī)之前,我們沒(méi)法刪除系統(tǒng)出場(chǎng)的 APP 的原因了。
  2. 解壓縮 APK,拷貝文件,創(chuàng)建應(yīng)用的數(shù)據(jù)目錄:為了加快 APP 的啟動(dòng)速度,APK 在安裝的時(shí)候,會(huì)首先將 APP 的可執(zhí)行文件 dex 拷貝到 /data/dalvik-cache 目錄,緩存起來(lái)。然后,在 /data/data/ 目錄下創(chuàng)建應(yīng)用程序的數(shù)據(jù)目錄 (以應(yīng)用的包名命名),存放在應(yīng)用的相關(guān)數(shù)據(jù),如數(shù)據(jù)庫(kù)、XML 文件、Cache、二進(jìn)制的 so 動(dòng)態(tài)庫(kù)等。
  3. 解析 APK 的 AndroidManifest.xml 文件。
    public PackageManagerService(Context context, Installer installer,boolean factoryTest, boolean onlyCore) {// ....synchronized (mInstallLock) {synchronized (mPackages) {// Expose private service for system components to use.LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());sUserManager = new UserManagerService(context, this,new UserDataPreparer(mInsstaller, mInstallLock, mContext, mOnlyCore), mPackages);mPermissionManager = PermissionManagerService.create(context,new DefaultPermissionGrantedCallback() {@Overridepublic void onDefaultRuntimePermissionsGranted(int userId) {synchronized(mPackages) {mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);}}}, mPackages /*externalLock*/);mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();mSettings = new Settings(mPermissionManager.getPermissionSettings(), mPackages);}}// ...mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context, "*dexopt*");DexManager.Listener dexManagerListener = DexLogger.getListener(this, installer, mInstallLock);mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock, dexManagerListener);mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);// ...synchronized (mInstallLock) {synchronized (mPackages) {// 創(chuàng)建消息mHandlerThread = new ServiceThread(TAG,Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);mHandlerThread.start();mHandler = new PackageHandler(mHandlerThread.getLooper());// ...// 掃描各個(gè)目錄獲取 APK 文件:VENDOR_OVERLAY_DIR           // framework 文件夾:frameworkDir// 系統(tǒng)文件夾:privilegedAppDir systemAppDir// 供應(yīng)商的包:Environment.getVendorDirectory()// 原始設(shè)備制造商的包 :Environment.getOdmDirectory()// 原始設(shè)計(jì)商的包:Environment.getOdmDirectory()// 原始產(chǎn)品的包:// ....mInstallerService = new PackageInstallerService(context, this);final Pair<ComponentName, String> instantAppResolverComponent = getInstantAppResolverLPr();if (instantAppResolverComponent != null) {mInstantAppResolverConnection = new InstantAppResolverConnection(mContext, instantAppResolverComponent.first,instantAppResolverComponent.second);mInstantAppResolverSettingsComponent =getInstantAppResolverSettingsLPr(instantAppResolverComponent.first);} else {mInstantAppResolverConnection = null;mInstantAppResolverSettingsComponent = null;}updateInstantAppInstallerLocked(null);final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();final int[] currentUserIds = UserManagerService.getInstance().getUserIds();for (int userId : currentUserIds) {userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());}mDexManager.load(userPackages);} // synchronized (mPackages)} // synchronized (mInstallLock)// ....}

在構(gòu)造方法中會(huì)掃描多個(gè)目錄來(lái)獲取 APK 文件,上述注釋中我們已經(jīng)給出了這些目錄,及其獲取的方式。當(dāng)掃描一個(gè)路徑的時(shí)候會(huì)使用 scanDirLI() 方法來(lái)完成掃描工作。

    private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {final File[] files = scanDir.listFiles();if (ArrayUtils.isEmpty(files)) {return;}try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, mParallelPackageParserCallback)) {int fileCount = 0;for (File file : files) {final boolean isPackage = (isApkFile(file) || file.isDirectory())&& !PackageInstallerService.isStageName(file.getName());if (!isPackage) {continue;}// 提交文件用來(lái)解析parallelPackageParser.submit(file, parseFlags);fileCount++;}for (; fileCount > 0; fileCount--) {// 獲取解析的結(jié)果,即從隊(duì)列阻塞隊(duì)列中獲取解析的結(jié)果ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();// ...if (throwable == null) {// TODO(toddke): move lower in the scan chain// Static shared libraries have synthetic package namesif (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {renameStaticSharedLibraryPackage(parseResult.pkg);}try {if (errorCode == PackageManager.INSTALL_SUCCEEDED) {scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags, currentTime, null);}} catch (PackageManagerException e) {errorCode = e.error;}}// 。。。}}}

從上面的代碼中可以看出,提交文件來(lái)解析以及獲取解析都是通過(guò) ParallelPackageParser 來(lái)完成的。它使用 submit() 方法來(lái)提交文件用來(lái)解析,使用 take() 方法獲取解析的結(jié)果。這兩個(gè)方法的定義如下,

    public void submit(File scanFile, int parseFlags) {mService.submit(() -> {ParseResult pr = new ParseResult();try {PackageParser pp = new PackageParser();pp.setSeparateProcesses(mSeparateProcesses);pp.setOnlyCoreApps(mOnlyCore);pp.setDisplayMetrics(mMetrics);pp.setCacheDir(mCacheDir);pp.setCallback(mPackageParserCallback);pr.scanFile = scanFile;pr.pkg = parsePackage(pp, scanFile, parseFlags);} catch (Throwable e) {pr.throwable = e;}try {mQueue.put(pr);} catch (InterruptedException e) {Thread.currentThread().interrupt();mInterruptedInThread = Thread.currentThread().getName();}});}public ParseResult take() {try {if (mInterruptedInThread != null) {throw new InterruptedException("Interrupted in " + mInterruptedInThread);}return mQueue.take();} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new IllegalStateException(e);}}

submit() 方法使用一個(gè)線程池來(lái)執(zhí)行任務(wù),也就是上面的 mService。它會(huì)將要解析的信息封裝成 PackageParser 對(duì)象,然后把解析的結(jié)果信息封裝成 ParseResult 放進(jìn)一個(gè)阻塞隊(duì)列中。當(dāng)調(diào)用 take() 方法的時(shí)候會(huì)從該阻塞隊(duì)列中獲取解析的結(jié)果。

包信息的解析最終是通過(guò) PackageParser 的 parsePackage() 方法來(lái)完成的。其定義如下,

    public Package parsePackage(File packageFile, int flags, boolean useCaches)throws PackageParserException {Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;if (parsed != null) {return parsed;}long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;if (packageFile.isDirectory()) {parsed = parseClusterPackage(packageFile, flags);} else {// 是文件,所以走這條路線parsed = parseMonolithicPackage(packageFile, flags);}long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;cacheResult(packageFile, flags, parsed);return parsed;}

我們會(huì)在這方法中進(jìn)入到 parseMonolithicPackage() 來(lái)對(duì)文件進(jìn)行解析。

    public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);try {// 解析final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);pkg.setCodePath(apkFile.getCanonicalPath());pkg.setUse32bitAbi(lite.use32bitAbi);return pkg;} catch (IOException e) {throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION);} finally {IoUtils.closeQuietly(assetLoader);}}

在這個(gè)方法中會(huì)使用 parseBaseApk() 來(lái)對(duì) APK 文件進(jìn)行解析,

    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)throws PackageParserException {final String apkPath = apkFile.getAbsolutePath();String volumeUuid = null;if (apkPath.startsWith(MNT_EXPAND)) {final int end = apkPath.indexOf('/', MNT_EXPAND.length());volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);}mParseError = PackageManager.INSTALL_SUCCEEDED;mArchiveSourcePath = apkFile.getAbsolutePath();XmlResourceParser parser = null;try {final int cookie = assets.findCookieForPath(apkPath);// 讀取 AndroidManifest.xmlparser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);final Resources res = new Resources(assets, mMetrics, null);final String[] outError = new String[1];// 在這里進(jìn)一步解析 Manifest 的各種信息final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);pkg.setVolumeUuid(volumeUuid);pkg.setApplicationVolumeUuid(volumeUuid);pkg.setBaseCodePath(apkPath);pkg.setSigningDetails(SigningDetails.UNKNOWN);return pkg;} catch (PackageParserException e) {throw e;} catch (Exception e) {throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION);} finally {IoUtils.closeQuietly(parser);}}

這里的 ANDROID_MANIFEST_FILENAME 是一個(gè)字符串,這個(gè)字符串的定義是 AndroidManifest.xml,所以,我們找到了解析 Manifest 的地方。

然后方法會(huì)進(jìn)入到 parseBaseApk() 方法中進(jìn)一步對(duì) Manifest 進(jìn)行解析。其讀取操作就是基本的 XML 解析的過(guò)程。它會(huì)使用內(nèi)部定義的字符串常量從 Manifest 中獲取應(yīng)用的版本還有四大組件等信息。

解析完了 APK 之后會(huì)一路經(jīng)過(guò) return 語(yǔ)句返回到 scanDirLI() 方法中,當(dāng)從阻塞隊(duì)列中取出 Package 之后將會(huì)調(diào)用 scanPackageChildLI() 在該方法中會(huì)將解析的出的 APK 信息緩存到 PMS 中。

這樣,在系統(tǒng)啟動(dòng)之后 PMS 就解析了全部的 APK 文件,并將其緩存到了 PMS 中。這樣這些應(yīng)用程序還無(wú)法展示給用戶,所以需要 Launcher 桌面程序從 PMS 中獲取安裝包信息并展示到桌面上。

2、應(yīng)用安裝的過(guò)程

雖然 PMS 用來(lái)負(fù)責(zé)應(yīng)用的安裝和卸載,但是真實(shí)的工作卻是交給 installd 來(lái)實(shí)現(xiàn)的。 installd 是在系統(tǒng)啟動(dòng)的時(shí)候,由 init 進(jìn)程解析 init.rc 文件創(chuàng)建的。在早期版本的 Android 中,它使用 Socket 與 Java 層的 Installer 進(jìn)行通信。在 9.0 的代碼中,它使用 Binder 與 Java 層的 Installer 進(jìn)行通信。當(dāng)啟動(dòng) Installd 的時(shí)候,將會(huì)調(diào)用其 main 方法,

int main(const int argc, char *argv[]) {return android::installd::installd_main(argc, argv);
}static int installd_main(const int argc ATTRIBUTE_UNUSED, char *argv[]) {int ret;int selinux_enabled = (is_selinux_enabled() > 0);setenv("ANDROID_LOG_TAGS", "*:v", 1);android::base::InitLogging(argv);SLOGI("installd firing up");union selinux_callback cb;cb.func_log = log_callback;selinux_set_callback(SELINUX_CB_LOG, cb);// 初始化全局信息if (!initialize_globals()) {exit(1);}// 初始化相關(guān)目錄if (initialize_directories() < 0) {exit(1);}if (selinux_enabled && selinux_status_open(true) < 0) {exit(1);}if ((ret = InstalldNativeService::start()) != android::OK) {exit(1);}// 加入到 Binder 線程池當(dāng)中IPCThreadState::self()->joinThreadPool();LOG(INFO) << "installd shutting down";return 0;
}

在啟動(dòng) Installd 的時(shí)候會(huì)初始化各種相關(guān)的目錄,這部分內(nèi)容就不展開(kāi)了。然后,它會(huì)調(diào)用 IPCThreadState::self()->joinThreadPool() 一行來(lái)將當(dāng)前線程池加入到 Binder 線程池當(dāng)中等待通信。

當(dāng) Java 層的 Installer 需要與之通信的時(shí)候,會(huì)調(diào)用 connect() 方法與之建立聯(lián)系。其源碼如下,這里會(huì)通過(guò) ServiceManager 獲取 installd 服務(wù),然后將其轉(zhuǎn)換成本地的服務(wù)進(jìn)行 IPC 的調(diào)用。

    private void connect() {// 獲取遠(yuǎn)程服務(wù) IBinder binder = ServiceManager.getService("installd");if (binder != null) {try {binder.linkToDeath(new DeathRecipient() {@Overridepublic void binderDied() {connect();}}, 0);} catch (RemoteException e) {binder = null;}}if (binder != null) {// 轉(zhuǎn)成本地服務(wù)進(jìn)行 IPC 調(diào)用mInstalld = IInstalld.Stub.asInterface(binder);try {invalidateMounts();} catch (InstallerException ignored) {}} else {// 重連BackgroundThread.getHandler().postDelayed(() -> {connect();}, DateUtils.SECOND_IN_MILLIS);}}

Installer 與 PMC 類似,也是一種系統(tǒng)服務(wù),它的啟動(dòng)的時(shí)刻與 PMS 基本一致,位于同一個(gè)方法中,并且其啟動(dòng)時(shí)刻位于 PMS 之前。

2、從 ADB 安裝的過(guò)程

另外
有什么技術(shù)問(wèn)題歡迎加我交流 qilebeaf
本人10多年大廠軟件開(kāi)發(fā)經(jīng)驗(yàn),精通Android,Java,Python,前端等開(kāi)發(fā),空余時(shí)間承接軟件開(kāi)發(fā)設(shè)計(jì)、課程設(shè)計(jì)指導(dǎo)、解決疑難bug、AI大模型搭建,AI繪圖應(yīng)用等。
歡迎砸單

http://aloenet.com.cn/news/41338.html

相關(guān)文章:

  • 免費(fèi)建站自己的網(wǎng)址域名注冊(cè)查詢官網(wǎng)
  • 網(wǎng)站建設(shè)好以后怎么管理百度關(guān)鍵詞搜索量統(tǒng)計(jì)
  • 數(shù)據(jù)庫(kù)網(wǎng)站制作北京seo推廣系統(tǒng)
  • 搜索引擎優(yōu)化大致包含哪些內(nèi)容或環(huán)節(jié)河北seo推廣公司
  • 建一個(gè)素材網(wǎng)站多少錢杭州網(wǎng)站制作排名
  • 廣州市荔灣區(qū)疫情最新消息重慶可靠的關(guān)鍵詞優(yōu)化研發(fā)
  • 可以做婚禮鮮花布置的網(wǎng)站外貿(mào)推廣平臺(tái)哪個(gè)好
  • 工業(yè)企業(yè)網(wǎng)站建設(shè)費(fèi)教育培訓(xùn)網(wǎng)站官網(wǎng)
  • 寶安網(wǎng)站制作公司合肥網(wǎng)絡(luò)seo推廣服務(wù)
  • wordpress圖片站點(diǎn)網(wǎng)站制作網(wǎng)站推廣
  • it培訓(xùn)網(wǎng)站模板seo小白入門教學(xué)
  • 做棋牌網(wǎng)站建設(shè)哪家便宜免費(fèi)數(shù)據(jù)查詢網(wǎng)站
  • 免費(fèi)網(wǎng)站制作案例汽車宣傳軟文
  • 微擎如何做網(wǎng)站百度我的訂單app
  • 網(wǎng)站開(kāi)發(fā)用python嗎推廣策劃方案范文
  • 做網(wǎng)站要錢嗎sem優(yōu)化公司
  • 北京新冠最新情況最新消息百度seo2022新算法更新
  • 亞馬遜網(wǎng)是b2b還是b2c廈門網(wǎng)站seo外包
  • 江門網(wǎng)站制作培訓(xùn)網(wǎng)頁(yè)seo優(yōu)化
  • 品牌建設(shè)網(wǎng)站規(guī)劃網(wǎng)店?duì)I銷與推廣策劃方案
  • 做網(wǎng)站需要多少人中國(guó)十大電商公司排名
  • 網(wǎng)站商城定制網(wǎng)站建設(shè)哪個(gè)平臺(tái)可以免費(fèi)發(fā)廣告
  • 簡(jiǎn)潔企業(yè)網(wǎng)站源碼專注于seo顧問(wèn)
  • 揭陽(yáng)cms建站模板數(shù)據(jù)分析師35歲以后怎么辦
  • wordpress調(diào)用js函數(shù)魔方優(yōu)化大師官網(wǎng)下載
  • 網(wǎng)絡(luò)規(guī)劃設(shè)計(jì) 網(wǎng)站建設(shè)seo視頻教程百度網(wǎng)盤
  • wap網(wǎng)站建設(shè)公司新聞?lì)^條今天最新消息
  • 帝國(guó)網(wǎng)站管理系統(tǒng)入門教程百度排名點(diǎn)擊軟件
  • 企業(yè)做網(wǎng)站有用嗎簡(jiǎn)述如何對(duì)網(wǎng)站進(jìn)行推廣
  • 做槍版電影網(wǎng)站賺錢免費(fèi)二級(jí)域名平臺(tái)