android – home键及launcher启动流程分析

  • Post author:
  • Post category:其他



android – home键及launcher启动流程分析

launcher,也就是android的桌面应用程序,开机启动的第一个应用程序及按home键进入的都是这个程序。

如果需要修改启动流程或者制作一个新的launcher,都有必要了解一下这个流程。


第一部分:系统默认Home应用程序(launcher)启动流程




1、frameworks/base/services/java/com/android/server/SystemServer.java

一直以来大家都记得”hello world”程序就是写一个main函数,那么我们这里也从main函数开始:

public static void main(String[] args)

这里分为两个过程:

SystemServer.init1

启动几个重要navtive service,比如 SurfaceFlinger、SensorService

SystemServer.init2

启动java service,比如 ContentService、PowerManagerService、MountService、WindowManagerService 等等

2、frameworks/base/services/java/com/android/server/am/ActivityManagerServcie.java



启动 ActivityManagerService跳到如下:

	 Slog.i(TAG, "Activity Manager");
   context = ActivityManagerService.main(factoryTest);
   
    public static final Context main(int factoryTest) {
        AThread thr = new AThread();
        thr.start();

        synchronized (thr) {
            while (thr.mService == null) {
                try {
                    thr.wait();
                } catch (InterruptedException e) {
                }
            }
        }

        ActivityManagerService m = thr.mService;
        mSelf = m;
        ActivityThread at = ActivityThread.systemMain();
        mSystemThread = at;
        Context context = at.getSystemContext();
        context.setTheme(android.R.style.Theme_Holo);
        m.mContext = context;
        m.mFactoryTest = factoryTest;
        m.mMainStack = new ActivityStack(m, context, true);
        
        m.mBatteryStatsService.publish(context);
        m.mUsageStatsService.publish(context);
        
        synchronized (thr) {
            thr.mReady = true;
            thr.notifyAll();
        }

        m.startRunning(null, null, null, null);
        
        return context;
    }
    


这个函数首先通过AThread线程对象来内部创建了一个ActivityManagerService实例,然后将这个实例保存其成员变量

mService中,接着又把这个ActivityManagerService实例保存在ActivityManagerService类的静态成员变量mSelf中,

最后初始化其它成员变量,就结束了。

AThread 线程启动代码如下:

    AThread thr = new AThread();
    thr.start();
       
    static class AThread extends Thread {
        ActivityManagerService mService;
        boolean mReady = false;

        public AThread() {
            super("ActivityManager");
        }

        public void run() {
            Looper.prepare();

            android.os.Process.setThreadPriority(
                    android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);

            ActivityManagerService m = new ActivityManagerService();

            synchronized (this) {
                mService = m;
                notifyAll();
            }

            synchronized (this) {
                while (!mReady) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
        ...
   	}   
   

3、ActivityManagerService.systemReady

ServerThread.run函数在将系统中的一系列服务都初始化完毕之后才调用

SystemService.java:

    // We now tell the activity manager it is okay to run third party
    // code.  It will call back into us once it has gotten to the state
    // where third party code can really run (but before it has actually
    // started launching the initial applications), for us to complete our
    // initialization.
    ActivityManagerService.self().systemReady(new Runnable() {
        public void run() {
            Slog.i(TAG, "Making services ready");

核心代码如下:

public final class ActivityManagerService extends ActivityManagerNative  
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
    ......  
    public void systemReady(final Runnable goingCallback) {  
        ......  
        synchronized (this) {  
            ......  
            mMainStack.resumeTopActivityLocked(null);  
        }  
    }  
    ......  
}

4、ActivityStack.resumeTopActivityLocked

    final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
        // Find the first activity that is not finishing.
        ActivityRecord next = topRunningActivityLocked(null);

        // Remember how we'll process this pause/resume situation, and ensure
        // that the state is reset however we wind up proceeding.
        final boolean userLeaving = mUserLeaving;
        mUserLeaving = false;

        if (next == null) {
            // There are no more activities!  Let's just start up the
            // Launcher...
            if (mMainStack) {
                ActivityOptions.abort(options);
                return mService.startHomeActivityLocked(mCurrentUser);
            }
        }
        
        ...
     }



这里调用函数topRunningActivityLocked返回的是当前系统Activity堆栈最顶端的Activity,由于此时还没有



Activity被启动过,因此,返回值为null,即next变量的值为null,于是就调用mService.startHomeActivityLocked函数


5、startHomeActivityLocked

		boolean startHomeActivityLocked(int userId) {
			...
			Intent intent = new Intent(
            mTopAction,
            mTopData != null ? Uri.parse(mTopData) : null);
        intent.setComponent(mTopComponent);
        if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
            intent.addCategory(Intent.CATEGORY_HOME);
        }
        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);
            if (app == null || app.instrumentationClass == null) {
                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                mMainStack.startActivityLocked(null, intent, null, aInfo,
                        null, null, 0, 0, 0, 0, null, false, null);
            }
        }

        return true;
    }
    

函数首先创建一个CATEGORY_HOME类型的Intent,然后通过Intent.resolveActivityInfo函数向PackageManagerService

查询Category类型为HOME的Activity,即 packages/apps/Launcher2/AndroidManifest.xml文件中所示:

这里就是将拼装好的 home intent 发送出去即可

    <activity  
            android:name="com.android.launcher2.Launcher"  
            android:launchMode="singleTask"  
            android:clearTaskOnLaunch="true"  
            android:stateNotNeeded="true"  
            android:theme="@style/Theme"  
            android:screenOrientation="nosensor"  
            android:windowSoftInputMode="stateUnspecified|adjustPan">  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
                <category android:name="android.intent.category.HOME" />  
                <category android:name="android.intent.category.DEFAULT" />  
                <category android:name="android.intent.category.MONKEY"/>  
                </intent-filter>  
   	</activity>

6、ResolverActivity.java



frameworks\base\core\java\com\android\internal\app\ResolverActivity.java

		/**
		 * This activity is displayed when the system attempts to start an Intent for
		 * which there is more than one matching activity, allowing the user to decide
		 * which to go to.  It is not normally used directly by application developers.
		 */
		public class ResolverActivity extends AlertActivity implements AdapterView.OnItemClickListener {
	



这是应用程序就是查找匹配的intent-filter应用程序,多于一个时则列表提示用户选择,默认或者只有一个则直接进入。

    mCurrentResolveList = mPm.queryIntentActivities(
            mIntent, PackageManager.MATCH_DEFAULT_ONLY);

最后以一个序列图总结下:






第二部分:按home键启动Home应用

既然是按键,这里就简要说明一下按键事件处理流程:

1、InputManager负责读取事件并把事件送到frameworks的java层

2、WindowManagerService里会有一个InputMonitor类来监听事件变化并做相应的分发处理。

3、在WindowManagerService会有一个WindowManagerPolicy来做消息拦截处理。

4、WindowManagerService会把消息发给最上面运行的窗口接收

5、这里最上面窗口就是 PhoneWindowManager



/**
 * WindowManagerPolicy implementation for the Android phone UI.  This
 * introduces a new method suffix, Lp, for an internal lock of the
 * PhoneWindowManager.  This is used to protect some internal state, and
 * can be acquired with either thw Lw and Li lock held, so has the restrictions
 * of both of those when held.
 */
public class PhoneWindowManager implements WindowManagerPolicy 

PhoneWindowManager 实现 Android UI

interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags)

这个方法就是预先处理按键消息的,即由系统处理,一般 HOME、MUTE、POWER等都是由系统先处理

    /** {@inheritDoc} */
    @Override
    public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
				...
        // First we always handle the home key here, so applications
        // can never break it, although if keyguard is on, we do let
        // it handle it, because that gives us the correct 5 second
        // timeout.
        if (keyCode == KeyEvent.KEYCODE_HOME) {
        	...
        	//单击home处理  
          launchHomeFromHotKey();  
        }
        
        ...
    }

下面就是处理home键的功能

    /**
     * A home key -> launch home action was detected.  Take the appropriate action
     * given the situation with the keyguard.
     */
    void launchHomeFromHotKey() {
        if (mKeyguardMediator != null && mKeyguardMediator.isShowingAndNotHidden()) {
            // don't launch home if keyguard showing
        } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
            // when in keyguard restricted mode, must first verify unlock
            // before launching home
            mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
                public void onKeyguardExitResult(boolean success) {
                    if (success) {
                        try {
                            ActivityManagerNative.getDefault().stopAppSwitches();
                        } catch (RemoteException e) {
                        }
                        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
                        startDockOrHome();
                    }
                }
            });
        } else {
            // no keyguard stuff to worry about, just launch home!
            try {
                ActivityManagerNative.getDefault().stopAppSwitches();
            } catch (RemoteException e) {
            }
            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
            startDockOrHome();
        }
    }
    

发送home intent出去:

    void startDockOrHome() {
        // We don't have dock home anymore. Home is home. If you lived here, you'd be home by now.
        mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT);
    }  

其中 mHomeIntent 是由init()函数初始化完成的

    mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
    mHomeIntent.addCategory(Intent.CATEGORY_HOME);
    mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);		

最后也是由 ResolverActivity 继续处理,上面已经讲过了,这里就略写了。





版权声明:本文为andyhuabing原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。