美文网首页framework学习笔记
framework学习笔记12. Launcher的启动过程

framework学习笔记12. Launcher的启动过程

作者: 加个标志位 | 来源:发表于2021-01-01 13:56 被阅读0次
    1. 启动入口分析:
      ActivityManagerService.java中
    Intent getHomeIntent() {
            Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
            intent.setComponent(mTopComponent);
            if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                intent.addCategory(Intent.CATEGORY_HOME); // 构建一个category为CATEGORY_HOME的Intent
            }
            return intent;
     }
    

    Android系统启动后,PMS会扫描apk信息,并保存 Manifest.xml 中相关的信息,这里的intent就是Intent.CATEGORY_HOME = "android.intent.category.HOME",这个category会在Launcher3的 AndroidManifest.xml中配置,然后PMS找到category为HOME的activity并启动它;

       boolean startHomeActivityLocked(int userId) {
            if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL && mTopAction == null) {
                return false;
            }
            Intent intent = getHomeIntent();
            ActivityInfo aInfo =
                resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
            if (aInfo != null) {
                intent.setComponent(new ComponentName(
                        aInfo.applicationInfo.packageName, aInfo.name));
                // Don't do this if the home app is currently being instrumented.
                aInfo = new ActivityInfo(aInfo);
                aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
                ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                        aInfo.applicationInfo.uid, true);
                if (app == null || app.instrumentationClass == null) {
                    intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                    mStackSupervisor.startHomeActivity(intent, aInfo);
                }
            }
    
            return true;
        }
    

    这里简单介绍一下intent.setComponent():

    // 启动自己写的应用程序,一个参数是应用程序的包名,后一个是这个应用程序的主Activity名
    Intent intent=new Intent();  
    intent.setComponent(
        new ComponentName("com.aaa.bbb.ccc.ddd","com.aaa.bbb.ccc.ddd.MainActivity"));  
    startActivity(intent); 
    
    // 启动系统自带的应用程序
    Intent intent=new Intent();  
    intent.setComponent(new ComponentName("com.android.calendar","com.android.calendar.LaunchActivity"));  
    startActivity(intent);   
    

    startHomeActivity:启动桌面的activity -> 分为两步,如果没有进程先创建进程,然后再启动activity;

    1. 获取所有 app 应用信息:Launcher.java
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
             // ...
            if (!mRestoring) {
                if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {
                    // If the user leaves launcher, then we should just load items asynchronously when
                    // they return.
                    mModel.startLoader(true, PagedView.INVALID_RESTORE_PAGE);
                } else {
                    // We only load the page synchronously if the user rotates (or triggers a
                    // configuration change) while launcher is in the foreground
                    mModel.startLoader(true, mWorkspace.getRestorePage());
                }
            }
    }
    
        public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {
            synchronized (mLock) {
                if (DEBUG_LOADERS) {
                    Log.d(TAG, "startLoader isLaunching=" + isLaunching);
                }
    
                // Clear any deferred bind-runnables from the synchronized load process
                // We must do this before any loading/binding is scheduled below.
                synchronized (mDeferredBindRunnables) {
                    mDeferredBindRunnables.clear();
                }
    
                // Don't bother to start the thread if we know it's not going to do anything
                if (mCallbacks != null && mCallbacks.get() != null) {
                    // If there is already one running, tell it to stop.
                    // also, don't downgrade isLaunching if we're already running
                    isLaunching = isLaunching || stopLoaderLocked();
                    mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);
                    if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
                            && mAllAppsLoaded && mWorkspaceLoaded) {
                        mLoaderTask.runBindSynchronousPage(synchronousBindPage);
                    } else {
                        sWorkerThread.setPriority(Thread.NORM_PRIORITY);
                        sWorker.post(mLoaderTask);
                    }
                }
            }
        }
    

    这里new了一个LoaderTask,startLoader主要是启动了一个线程,用于加载数据;sWorker是一个Handle对象,用于启动线程的run方法。接下来看看LoaderTask中的run()方法:简化代码

        //LauncherModel内部类LoaderTask中的run()方法:
         public void run() {
                boolean isUpgrade = false;
    
                synchronized (mLock) {
                    mIsLoaderTaskRunning = true;
                }
                keep_running: {
                    isUpgrade = loadAndBindWorkspace();
                    if (mStopped) {
                        break keep_running;
                    }
    
                    waitForIdle();
                    loadAndBindAllApps(); //主要在这个方法中
                    // Restore the default thread priority after we are done loading items
                    synchronized (mLock) {
                        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
                    }
                }
    
                synchronized (sBgLock) {
                    for (Object key : sBgDbIconCache.keySet()) {
                        updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));
                    }
                    sBgDbIconCache.clear();
                }
    
                if (LauncherAppState.isDisableAllApps()) {
                    if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {
                        verifyApplications();
                    }
                }
    
                mContext = null;
                synchronized (mLock) {
                    // If we are still the last one to be scheduled, remove ourselves.
                    if (mLoaderTask == this) {
                        mLoaderTask = null;
                    }
                    mIsLoaderTaskRunning = false;
                }
            }
    
     //loadAndBindAllApps()方法:
     private void loadAndBindAllApps() {
                if (DEBUG_LOADERS) {
                    Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);
                }
                if (!mAllAppsLoaded) {
                    loadAllApps();  //调用了loadAllApps()方法
                    synchronized (LoaderTask.this) {
                        if (mStopped) {
                            return;
                        }
                        mAllAppsLoaded = true;
                    }
                } else {
                    onlyBindAllApps();
                }
            }
    

    我们在看看LoaderTask类中的loadAllApps()方法中做了哪些事情:

            private void loadAllApps() {
                final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
    
                final Callbacks oldCallbacks = mCallbacks.get();
                if (oldCallbacks == null) {
                    // This launcher has exited and nobody bothered to tell us.  Just bail.
                    Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");
                    return;
                }
    
                final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
                mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    
                final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();
    
                // Clear the list of apps
                mBgAllAppsList.clear();
                for (UserHandleCompat user : profiles) {
                    // Query for the set of apps
                    final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
                    // 获取launcher中所有ActivityInfo的信息;注释1
                    List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user); //注释2
                  
                    // Fail if we don't have any apps
                    if (apps == null || apps.isEmpty()) {
                        return;
                    }
                    // Sort the applications by name
                    final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
                    Collections.sort(apps,
                            new LauncherModel.ShortcutNameComparator(mLabelCache)); 
    
                    // Create the ApplicationInfos
                    for (int i = 0; i < apps.size(); i++) {
                        LauncherActivityInfoCompat app = apps.get(i);
                        // This builds the icon bitmaps.
                        mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache));
                    }
                }
                // Huh? Shouldn't this be inside the Runnable below?
                final ArrayList<AppInfo> added = mBgAllAppsList.added;
                mBgAllAppsList.added = new ArrayList<AppInfo>();
    
                // Post callback on main thread
                mHandler.post(new Runnable() {
                    public void run() {
                        final long bindTime = SystemClock.uptimeMillis();
                        final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                        if (callbacks != null) {
                            callbacks.bindAllApplications(added); //点击事件,见3
                        } else {
                            Log.i(TAG, "not binding apps: no Launcher activity");
                        }
                    }
                });
            }
    

    注释1:获取桌面app的基本信息,例如微信桌面图标中显示小红点,就是根据这个获取的;

    public abstract class LauncherActivityInfoCompat {
        LauncherActivityInfoCompat() {
        }
        // 包名,主activity的class名字
        public abstract ComponentName getComponentName();
        public abstract UserHandleCompat getUser();
        public abstract CharSequence getLabel();
        public abstract Drawable getIcon(int density);
        // 应用的信息,PMS解析,点击图标启动activity就需要这些信息
        public abstract ApplicationInfo getApplicationInfo(); 
        public abstract long getFirstInstallTime();
        public abstract Drawable getBadgedIcon(int density);
    }
    

    注释2:mLauncherApps 是 LauncherAppsCompat,我们看看它的初始化:

     // LauncherModel 中:
     LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
            Context context = app.getContext();
             // ...
             // 在LauncherModel的构造函数中初始化
            mLauncherApps = LauncherAppsCompat.getInstance(context); 
            mUserManager = UserManagerCompat.getInstance(context);
     }
    
       // LauncherAppsCompat类中:单例模式
       public static LauncherAppsCompat getInstance(Context context) {
            synchronized (sInstanceLock) {
                if (sInstance == null) {
                    if (Utilities.isLmpOrAbove()) {
                        sInstance = new LauncherAppsCompatVL(context.getApplicationContext());
                    } else { // 都行,就看这个吧
                        sInstance = new LauncherAppsCompatV16(context.getApplicationContext()); 
                    }
                }
                return sInstance;
            }
      }
    

    这里比较关键,mainIntent 中添加了 Intent.ACTION_MAIN 和 Intent.CATEGORY_LAUNCHER,这两条信息会在PackageManagerService查询activity时起到关键的筛查作用,这两条信息也就是App启动时开启的acitivity;

     public List<LauncherActivityInfoCompat> getActivityList(String packageName,
                UserHandleCompat user) {
            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); //查询每个app启动的主界面;
            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
            mainIntent.setPackage(packageName);
            List<ResolveInfo> infos = mPm.queryIntentActivities(mainIntent, 0); //PMS查询,跨进程通信;
            List<LauncherActivityInfoCompat> list =
                    new ArrayList<LauncherActivityInfoCompat>(infos.size());
            for (ResolveInfo info : infos) {
                list.add(new LauncherActivityInfoCompatV16(mContext, info)); 
            }
            return list;
        }
    
    1. 填充桌面数据处理点击:callbacks.bindAllApplications(added);
      LoaderTask类中的tryGetCallbacks()
           Callbacks tryGetCallbacks(Callbacks oldCallbacks) {
                synchronized (mLock) {
                    if (mStopped) {
                        return null;
                    }
    
                    if (mCallbacks == null) {
                        return null;
                    }
    
                    final Callbacks callbacks = mCallbacks.get();
                    if (callbacks != oldCallbacks) {
                        return null;
                    }
                    if (callbacks == null) {
                        Log.w(TAG, "no mCallbacks");
                        return null;
                    }
    
                    return callbacks;
                }
            }
    
    
    //LauncherModel类中对mCallbacks进行初始化的:initialize()方法中
    public void initialize(Callbacks callbacks) {
            synchronized (mLock) {
                mCallbacks = new WeakReference<Callbacks>(callbacks);
            }
    }
    

    Laucher.java中的点击事件:

    public void onClick(View v) {
            // Make sure that rogue clicks don't get through while allapps is launching, or after the
            // view has detached (it's possible for this to happen if the view is removed mid touch).
            if (v.getWindowToken() == null) {
                return;
            }
    
            if (!mWorkspace.isFinishedSwitchingState()) {
                return;
            }
    
            if (v instanceof Workspace) {
                if (mWorkspace.isInOverviewMode()) {
                    mWorkspace.exitOverviewMode(true);
                }
                return;
            }
    
            if (v instanceof CellLayout) {
                if (mWorkspace.isInOverviewMode()) {
                    mWorkspace.exitOverviewMode(mWorkspace.indexOfChild(v), true);
                }
            }
    
            Object tag = v.getTag();
            if (tag instanceof ShortcutInfo) {
                onClickAppShortcut(v);
            } else if (tag instanceof FolderInfo) {
                if (v instanceof FolderIcon) {
                    onClickFolderIcon(v);
                }
            } else if (v == mAllAppsButton) {
                onClickAllAppsButton(v);  // 所有app展示页的点击事件
            } else if (tag instanceof AppInfo) {
                startAppShortcutOrInfoActivity(v);  // 具体app图标的点击事件:启动app
            } else if (tag instanceof LauncherAppWidgetInfo) {
                if (v instanceof PendingAppWidgetHostView) {
                    onClickPendingWidget((PendingAppWidgetHostView) v);
                }
            }
        }
    

    具体app图标的点击事件:

     private void startAppShortcutOrInfoActivity(View v) {
            // ... 省略部分代码
            boolean success = startActivitySafely(v, intent, tag);  // 真正启动应用activity 注释3
            mStats.recordLaunch(intent, shortcut);
    
            if (success && v instanceof BubbleTextView) {
                mWaitingForResume = (BubbleTextView) v;
                mWaitingForResume.setStayPressed(true);
            }
        }
    
    
        // 这里的 intent 是AppInfo中的intent
        public AppInfo(Context context, LauncherActivityInfoCompat info, UserHandleCompat user,
                IconCache iconCache, HashMap<Object, CharSequence> labelCache) {
            this.componentName = info.getComponentName();
            this.container = ItemInfo.NO_ID;
    
            flags = initFlags(info);
            firstInstallTime = info.getFirstInstallTime();
            iconCache.getTitleAndIcon(this, info, labelCache);
            intent = new Intent(Intent.ACTION_MAIN);
            intent.addCategory(Intent.CATEGORY_LAUNCHER);
            // info.getComponentName() -> ComponentName中有packageName 和 class;
            intent.setComponent(info.getComponentName());
            intet.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) // 需要一个新的Task
            long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
            intent.putExtra(EXTRA_PROFILE, serialNumber);
            this.user = user;
        }
    

    注释3:startActivitySafely()

        boolean startActivitySafely(View v, Intent intent, Object tag) {
            boolean success = false;
            if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
                Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
                return false;
            }
            try {
                success = startActivity(v, intent, tag);  // startActivity
            } catch (ActivityNotFoundException e) {
                Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
            }
            return success;
        }
    
    
        boolean startActivity(View v, Intent intent, Object tag) {
            //代码重复?这里我也有一点不太懂为什么这么做
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            try {
                // Only launch using the new animation if the shortcut has not opted out (this is a
                // private contract between launcher and may be ignored in the future).
                boolean useLaunchAnimation = (v != null) &&
                        !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
                LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(this);
                UserManagerCompat userManager = UserManagerCompat.getInstance(this);
    
                UserHandleCompat user = null;
                if (intent.hasExtra(AppInfo.EXTRA_PROFILE)) {
                    long serialNumber = intent.getLongExtra(AppInfo.EXTRA_PROFILE, -1);
                    user = userManager.getUserForSerialNumber(serialNumber);
                }
    
                Bundle optsBundle = null;
                if (useLaunchAnimation) {
                    ActivityOptions opts = Utilities.isLmpOrAbove() ?
                            ActivityOptions.makeCustomAnimation(this, R.anim.task_open_enter, R.anim.no_anim) :
                            ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
                    optsBundle = opts.toBundle();
                }
    
                if (user == null || user.equals(UserHandleCompat.myUserHandle())) {
                    // Could be launching some bookkeeping activity
                    startActivity(intent, optsBundle);
                } else {
                    // TODO Component can be null when shortcuts are supported for secondary user
                    //这里最终也是mContext.startActivity(launchIntent, opts);
                    launcherApps.startActivityForProfile(intent.getComponent(), user,
                            intent.getSourceBounds(), optsBundle); 
                }
                return true;
            } catch (SecurityException e) {
                Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                Log.e(TAG, "Launcher does not have the permission to launch " + intent +
                        ". Make sure to create a MAIN intent-filter for the corresponding activity " +
                        "or use the exported attribute for this activity. "
                        + "tag="+ tag + " intent=" + intent, e);
            }
            return false;
        }
    

    相关文章

      网友评论

        本文标题:framework学习笔记12. Launcher的启动过程

        本文链接:https://www.haomeiwen.com/subject/hwltoktx.html