1. 程式人生 > >Android系統預設Home(Launcher)的啟動過程小結

Android系統預設Home(Launcher)的啟動過程小結

http://blog.csdn.net/happy08god/article/details/24265167

      Android系統開機,各個應用是如何載入並被顯示到桌面上的呢?帶著這份好奇,閱讀了在

AndroidManifest.xml 會被解析,解析得到的application,service和activity等資訊儲存在

PackageManagerService中。

      但是我們進入HOME介面,是要看到各個android app的快捷圖示和名稱的。顯示app的這些資訊,

就是我們的HOME,也就是Launcher乾的事情了。程式碼流程是從SystemServer 開始的,呼叫棧為:

ServerThread::run ( SystemServer.Java) ——>  ActivityManagerService::main (ActivityManagerService.java)

——> ActivityManagerService:: startRunning ——> ActivityManagerService::systemReady ——> 

ActivityStack::resumeTopActivityLocked ——> ActivityManagerService::startHomeActivityLocked


 其中startHomeActivityLocked函式首先建立一個CATEGORY_HOME型別的Intent,然後通過

Intent.resolveActivityInfo函式向PackageManagerService查詢Category型別為HOME的Activity。

這裡只有系統自帶的Launcher應用程式註冊了HOME型別的Activity

(見packages/apps/Launcher2/AndroidManifest.xml檔案):

  1. <activity
  2.             android:name="com.android.launcher2.Launcher"
  3.             android:launchMode="singleTask"
  4.             android:clearTaskOnLaunch="true"
  5.             android:stateNotNeeded="true"
  6.             android:theme="@style/Theme"
  7.             android:configChanges="mcc|mnc"
  8.             android:windowSoftInputMode="adjustPan"
  9.             android:screenOrientation="nosensor">
  10.             <intent-filter>
  11.                 <actionandroid:name="android.intent.action.MAIN"/>
  12.                 <categoryandroid:name="android.intent.category.HOME"/>
  13.                 <categoryandroid:name="android.intent.category.DEFAULT"/>
  14.                 <categoryandroid:name="android.intent.category.MONKEY"/>
  15.             </intent-filter>
  16. </activity>

最終,com.android.launcher2.Launcher被啟動起來,其onCreate函式被呼叫。具體可參考

Android應用程式啟動過程原始碼分析  一文。 在activity start流程中,performLaunchActivity

呼叫。裡面的mInstrumentation.callActivityOnCreate(activity, r.state); 呼叫的就是Instrumentation

類的callActivityOnCreate方法。呼叫堆疊為:ActivityThread::performLaunchActivity ——> 

Instrumentation::callActivityOnCreate ——>  Activity::performCreate ——> onCreate(icicle); 

最後這個就是建立的Launcher 這個Activity覆蓋的onCreate方法。至此,Launcher.onCreate

被呼叫了。接下來的呼叫流程為:Launcher.onCreate ——> LauncherModel.startLoader ——> 

LoaderTask.run ——> LoaderTask.loadAndBindAllApps ——> LoaderTask.loadAllAppsByBatch

      函式首先構造一個CATEGORY_LAUNCHER型別的Intent:

  1. final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);  
  2. mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);  

接著從mContext變數中獲得PackageManagerService的介面:

  1. final PackageManager packageManager = mContext.getPackageManager();  

       下一步就是通過這個PackageManagerService.queryIntentActivities介面來查詢所有Action

型別為Intent.ACTION_MAIN,並且Category型別為Intent.CATEGORY_LAUNCHER的Activity了。

  1. final PackageManager packageManager = mContext.getPackageManager();  
  2. List<ResolveInfo> apps = null;  
  3. ...  
  4. ...  
  5. apps = packageManager.queryIntentActivities(mainIntent, 0);  

      PackageManagerService會把系統中的應用程式都解析一遍,然後把解析得到的Activity都儲存在

mActivities變數中,這裡通過這個mActivities變數的queryIntent函式返回符合條件intent的Activity,這裡

返回的便是Action型別為Intent.ACTION_MAIN,並且Category型別為Intent.CATEGORY_LAUNCHER

的Activity了。

終於知道我們自己寫的app的入口activity為啥要設定這樣的action和Category了吧?? 

  1. for (int j=0; i<N && j<batchSize; j++) {  
  2.      // This builds the icon bitmaps.
  3.      mBgAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i),  
  4.      mIconCache, mLabelCache));  
  5.      i++;  
  6. }  
  1. final ArrayList<ApplicationInfo> added = mBgAllAppsList.added;  
  2. mBgAllAppsList.added = new ArrayList<ApplicationInfo>();  
  1. if (first) {  
  2.      callbacks.bindAllApplications(added);  
  3. else {  
  4.       callbacks.bindAppsAdded(added);  
  5. }  
各個app的入口activity資訊將會被用於構造ApplicationInfo物件。上面的new ApplicationInfo

通過呼叫建構函式,將icon設定。

  1. public ApplicationInfo(PackageManager pm, ResolveInfo info, IconCache iconCache,  
  2.            HashMap<Object, CharSequence> labelCache) {  
  3.        final String packageName = info.activityInfo.applicationInfo.packageName;  
  4.        this.componentName = new ComponentName(packageName, info.activityInfo.name);  
  5.        this.container = ItemInfo.NO_ID;  
  6.        this.setActivity(componentName,  
  7.                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);  
  8.        try {  
  9.            int appFlags = pm.getApplicationInfo(packageName, 0).flags;  
  10.            if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {  
  11.                flags |= DOWNLOADED_FLAG;  
  12.                if ((appFlags & android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {  
  13.                    flags |= UPDATED_SYSTEM_APP_FLAG;  
  14.                }  
  15.            }  
  16.            firstInstallTime = pm.getPackageInfo(packageName, 0).firstInstallTime;  
  17.        } catch (NameNotFoundException e) {  
  18.            Log.d(TAG, "PackageManager.getApplicationInfo failed for " + packageName);  
  19.        }  
  20.        iconCache.getTitleAndIcon(this, info, labelCache);  
  21.    }  

  1. publicvoid getTitleAndIcon(ApplicationInfo application, ResolveInfo info,  
  2.            HashMap<Object, CharSequence> labelCache) {  
  3.        synchronized (mCache) {  
  4.            CacheEntry entry = cacheLocked(application.componentName, info, labelCache);  
  5.            application.title = entry.title;  
  6.            application.iconBitmap = entry.icon;  
  7.        }  
  8.    }  

  1. private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info,  
  2.            HashMap<Object, CharSequence> labelCache) {  
  3.        if (LauncherLog.DEBUG_LAYOUT) {  
  4.            LauncherLog.d(TAG, "cacheLocked: componentName = " + componentName  
  5.                    + ", info = " + info + ", HashMap<Object, CharSequence>:size = "
  6.                    +  ((labelCache == null) ? "null" : labelCache.size()));  
  7.        }  
  8.        CacheEntry entry = mCache.get(componentName);  
  9.        if (entry == null) {  
  10.            entry = new CacheEntry();  
  11.            mCache.put(componentName, entry);  
  12.            ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info);  
  13. 相關推薦

    Android系統預設HomeLauncher啟動過程小結

    http://blog.csdn.net/happy08god/article/details/24265167       Android系統開機,各個應用是如何載入並被顯示到桌面上的呢?帶著這份好奇,閱讀了在 AndroidManifest.xml 會

    Android 8.0系統原始碼分析--openCameraHAL啟動過程原始碼分析

         前面我們詳細分析了從應用層呼叫CameraManager的openCamera的方法來開啟相機的邏輯,上次的分析我們來到了CameraServer程序當中,但是還沒有真正看到open操作裝置節點來實現真正開啟的邏輯,遺留的問題也就是從frameworks\av\se

    Android系統應用開發Android framework系統預設設定修改

    launcher 總結:  1、launcher的佈局太居中,要想兩邊拉伸 <\packages\apps\Launcher2\res\values\dimens.xml> <dimen name="apps_customize_pageLayo

    Android系統預設設定開機第一次後的設定

    http://www.cnblogs.com/sardine /frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.jpg /packages/wallpapers/Basic/src/com/android/wallpaper/nex

    android開發系列教程啟動

    1.啟動頁延時跳轉+沉浸狀態列+啟動頁圖片全屏 public class SplashActivity extends AppCompatActivity { @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)

    Android效能優化筆記——啟動優化

    參考文章:  https://time.geekbang.org/column/article/73651 https://mp.weixin.qq.com/s/eaArt5Udc4WZ3NoH5RlEkQ https://juejin.im/post/5874bff0128fe1006b4

    Hook android系統呼叫研究

    一、Android核心原始碼的編譯環境 系統環境:Ubuntu 14.04 x64bit Android系統版本:Android 4.4.4 r1 Android核心版本:android-msm-hammerhead-3.4-kitkat-mr1 手機裝置:Nexus

    Android系統應用開發遮蔽狀態列下拉

    網上關於遮蔽狀態列的文章搜到不少,但都是針對某個應用,或者鎖屏狀態,才能遮蔽狀態列的下拉,而我的需求是不管任意狀態都遮蔽狀態列下拉,百度到的也可能版本不一樣,說的一些檔案都找不到,搜到一篇文章,自己修改了一個方法,然後OK了,具體如下: 檔案位置:frameworks

    Android系統修改彙總MTK

    以下都是基於Android 6.0 的程式碼去修改的!!! 十四、將桌面workspace、hotseat 大小調整 放大一半 , 這個要根據自己的需求來制定  workspace.setPadding(padding.left/

    Android系統應用開發系統語言以及新增字型庫

    1.如何向android的setting語言列表中新增一門語言 第一種:修改配置檔案 位置:build/target/product/languages_full.mk| languages_small.mk,這兩個檔案裡頭,有PRODUCT_LOCALES := en_U

    一步步淺析Android系統導航欄NavigationBar

    Android手機可分為有導航欄以及沒導航欄兩種,一般有物理按鍵的機器不會帶有導航欄,而沒有物理按鍵的機器則基本會帶,比如華為的手機基本都是帶導航欄的。 導航欄是如何載入到桌面上?是如何實現與物理按鍵相同的功能的呢?帶著種種疑問,我們來read the fuc

    android系統功能呼叫Notification、廣播開機自啟動、A應用啟動B應用

    首先,我來一個整體概括:新建一個app,設定開機自動啟動,然後建立一個notification,當用戶點選notification時,啟動另一個應用程式,好了,廢話多說,讓我們來看程式碼吧! java文件 private Button button; int

    Android原始碼解析之-->Launcher啟動流程

    上一篇文章中我們講解了關於SystemServer程序相關的知識,我們知道SystemServer程序主要用於啟動系統的各種服務,二者其中就包含了負責啟動Launcher的服務,LauncherAppService。具體更多關於SystenServer的啟動

    android TV 系統記憶體使用情況分析系統預設分配記憶體小

    系統記憶體申請分為預設記憶體和最大限度使用記憶體,一般沒有在AndroidMenifest中設定LargeHeap為true的話,使用的是預設記憶體,有些記憶體分配的很小比如48M,設定了之後就可以使用分配的最大記憶體空間了。下面是可以檢測記憶體使用量的計算方式。 // l

    Pro Android學習筆記 ActionBar1Home圖標區

    ces tom 新的 方便 find rac vertica lba manifest ?? Pro Android學習筆記(四八):ActionBar(1):Home圖標區 2013年03月10日 ? 綜合 ? 共 3256字 ? 字號 小 中 大 ? 評論關閉

    android hardware 簡述Android系統原始碼情景分析 筆記

    轉自 https://blog.csdn.net/u013377887/article/details/52965988   1.Android原始碼開發的C可執行原始檔一般存在external目錄下  2  Android的幾層框架.  &n

    KaliUbuntu啟動 WPS 後,出現提示系統缺失字型 解決辦法

    注:轉自:http://www.cnblogs.com/liangml/p/5969404.html 啟動WPS for Linux後,出現提示"系統缺失字型" 。 出現提示的原因是因為WPS for Linux沒有自帶windows的字型,只要在Linux系統中載入字型即可。 具體操作

    Android 外掛化分析3- Activity啟動流程

    在真正分析外掛化技術前,我們必須瞭解一些必要的關於Android四大元件的相關知識。 以Activity為例,我們需要了解Activity啟動過程,才能有效的進行Hook實現外掛化。 以Android 8.1為例 我們啟動一個Activity通常會使用startActi

    計算機從加電到系統Linux啟動完成

    0x0 背景 在我參加的面試和我面試別人、或者參加別人對別人的面試的事後經常遇到的一個問題就是:請從計算機加電開始描述一下計算機啟動到作業系統正式啟動起來的全過程。這是一個考驗對計算機體系結構和基本知識瞭解程度的問題。今天也就特別針對這個問題做一個回答,答案是基於80x86結構Linux 2.6及更

    Android 4.4 Graphic系統詳解2 VSYNC的生成

    VSYNC 的概念 VSYNC(Vertical Synchronization)是一個相當古老的概念,對於遊戲玩家,它有一個更加大名鼎鼎的中文名字—-垂直同步。 “垂直同步(vsync)”指的是顯示卡的輸出幀數和螢幕的垂直重新整理率相同,這完全是一個CRT顯