Android启动(六)Launcer的启动

Launcher 启动

  • Launcher是桌面应用程序 基于8.0 ,所以他的启动与应用程序启动类似,区别在于

    • launcher 是系统第一个程序,调用方法栈传递的参数多数为空
    • 应用呢 则是通过点击Launcher启动,调用方法栈传递参数多数不为空,二者大体流程相同 都是启动新进程在启动首页
  • 都是调用栈,只说调用栈的话,跟没说一样,所以这里先总结一下流程

  • 如果不了解Activity栈管理相关类 可以参看Activity栈管理类

流程总结

在SystemServer启动文章中我们最后提到,SyetemServer进程在启动的过程中会启动PackageManagerService,PackageManagerService启动后会将系统中的应用程序安装完成。在此前已经启动的ActivityManagerService会将Launcher启动起来。入口就在Ams的systemReady()里Launcher的启动

  1. 通过AMS启动launcher,这个过程在pms启动所有应用之前,所以此时栈中没有任何活动
  2. 要想启动launcher,就得先获取启动 launcher的Intent,并设置其在单独的一个栈中启动
    • 这里通过packageManagerService,查询注册Category类型为HOME的Activity的相关信息并设置给Intent,这个Activiy就是Launcher
      • 类型为Home 说明当 设备启动时 这是主活动,即显示的第一个活动,符合条件的这里应该就是Launcher了
    • 设置Intent 在新的栈中启动
  3. 然后通过AMS启动该Activity
    • 此时会先判断当前Activity所属进程是否存在
      • 存在就直接启动Activity
      • 不存在就 让AMS通知给zygote 先fork 一个进程,fork完了之后启动该进程
        • 启动进程的时候会调用ActivityThread的main 函数 ,main函数里调用attach方法,通过Binder给AMS 设置一个AppLicationThread 类型的Binder对象,这样AMS 通过这个BInder对象就能和launcher 交互了
  4. 当进程启动完了之后AMS会检测 是否有等待进程启动后才执行的Activity
    • 这里当launcher进程启动后,之前要启动的LauncherActivity 还没执行呢
    • 所以这里就要去启动launcher 进程的主界面了,
      • AMS通过调用AppLicationThread#scheduleLaunchActivity
        • 这里就是通过Binder驱动最终执行到了ActivityThread#scheduleLaunchActivity
      • 这个主界面(Launcher)本身就是一个Activity
      • 为了方便我们就叫它LauncherActivity

上面就是整体流程总结了

可能有点乱,有问题欢迎指出来谢谢

代码分析

1.1 SystemServer#通过AMS管理启动launcher

public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
        ...
        mStackSupervisor.resumeFocusedStackTopActivityLocked();
        mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
        traceLog.traceEnd(); // ActivityManagerStartApps
        traceLog.traceEnd(); // PhaseActivityManagerReady
}

Ams.systemready#StackSupervisor.resumeFocusedStackTopActivityLocked()

恢复当前焦点栈顶的Activity

boolean resumeFocusedStackTopActivityLocked() {
    	//调用该方法 传递参数全部为null 
        return resumeFocusedStackTopActivityLocked(null, null, null);
}
boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack,
                                  ActivityRecord target, ActivityOptions targetOptions) {
		//刚启动launcher ActivityRecord是空的
        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
        if (r == null || !r.isState(RESUMED)) {
            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
        } else if (r.isState(RESUMED)) {
            mFocusedStack.executeAppTransition(targetOptions);
        }
        return false;
    }

取可运行的栈顶ActivityRecord 因为这里启动的是Launcher 在此之前没有其他活动,所以取值一定为null

此时调用了

ActivityStack#resumeTopActivityUncheckedLocked(null,null)向下执行

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
     result = resumeTopActivityInnerLocked(prev, options);
}

参数传递,继续执行 调用

ActivityStack#resumeTopActivityInnerLocked(null,null)

在这里 启动launcher 和启动其他应用开有了区别

启动launcher 参数都为空 会向下执行调用到

  • mStackSupervisor.resumeHomeStackTask(prev, reason)

启动其他应用时 因为launcher已经启动 栈中有活动所以参数不为空会调用

  • mStackSupervisor.startSpecificActivityLocked(next, true, true)
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
       //在此堆栈中查找要恢复的下一个最上面的活动,且是可恢复的
       final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
       final boolean hasRunningActivity = next != null;
 		...
       if (!hasRunningActivity) {
           // 堆栈中没有剩余的活动,让我们看看其他地方。 
           // 应该是走到这里的代码 因为当前是启动launcher prev 是空的 
           // 后面所有方法中判断prev是空的代码都不会执行
           return resumeTopActivityInNextFocusableStack(prev, options, "noMoreActivities");
       }
}

获取要恢复且允许恢复的活动

这里next 是空的,栈中此时什么都没有 launcher 还没启动 所以继续向下执行

又是一个参数传递区别就是多了个参数 String reason = “noMoreActivities”

ActivityStack# resumeTopActivityInNextFocusableStack(prev, options, "noMoreActivities")

private boolean resumeTopActivityInNextFocusableStack(ActivityRecord prev,
          ActivityOptions options, String reason) {
      if ((!mFullscreen || !isOnHomeDisplay()) && adjustFocusToNextFocusableStackLocked(reason)) {
				//如过没有HomeStack 则移动到下一个栈FocusedStack
          return mStackSupervisor.resumeFocusedStackTopActivityLocked(
                  mStackSupervisor.getFocusedStack(), prev, null);
      }
     // Let's just start up the Launcher... 如果存在HomeStack,让我们启动Launcher
      ActivityOptions.abort(options);
      // 仅当主屏幕可见时才恢复Activity,这里英文直译过来就是这意思, 此时也就是Launcher
      return isOnHomeDisplay() &&
              mStackSupervisor.resumeHomeStackTask(prev, reason);
  }

传递参数向下执行

  • ActivityStackSupervisor.resumeHomeStackTask(prev, reason)

  • 此时prev=null reason ="noMoreActivities"

boolean resumeHomeStackTask(ActivityRecord prev, String reason) {       
       if (prev != null) {
           // 指示恢复任务堆栈中此类型下的任务。这一步暂时不用管,因为prev 是空的
           prev.getTask().setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
       }
    	//将焦点activites 调整到HomeStack中栈顶的位置 
       mHomeStack.moveHomeStackTaskToTop();
    	//从HomeStack中获取活动 HomeActivity
       ActivityRecord r = getHomeActivity();
       final String myReason = reason + " resumeHomeStackTask";
 
       //HomeActivity不为空,且未被finish 这是launcher,所以这里目前也不用考虑
       if (r != null && !r.finishing) {
           moveFocusableActivityStackToFrontLocked(r, myReason);
           return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
       }
    	//通过AMS调用到了startHomeActivityLocked
       return mService.startHomeActivityLocked(mCurrentUser, myReason);
   }

mService就是AMS 参数传递向下执行

AMS#startHomeActivityLocked(mCurrentUser, myReason)

1.2 获取启动Launcher的Intent

boolean startHomeActivityLocked(int userId, String reason) {
		//1 获取Intnet-》创建一个CATEGORY_HOME类型的Intent
        Intent intent = getHomeIntent();
    	//2 根据intent,通过resolveActivityInfo函数向PackageManagerService查询Category类型为HOME的Activity,并收集相关信息,这里我们假设只有系统自带的Launcher应用程序注册了HOME类型的Activity
        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
        if (aInfo != null) {
            //3 获取到之后给Intent 设置包名
           intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
           aInfo = new ActivityInfo(aInfo);
           aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);	//由于是第一次启动这个Launcher,接下来调用函数getProcessRecordLocked返回来的ProcessRecord值为null
            ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                    aInfo.applicationInfo.uid, true);
            if (app == null || app.instr == null) {
                //4 设置falg,启动在一个新的task
                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
                final String myReason = reason + ":" + userId + ":" + resolvedUserId;
                //启动新的Activity
                mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);
            }
        } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }

        return true;
    }
//创建一个CATEGORY_HOME类型的Intent
 Intent getHomeIntent() {
        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
        intent.setComponent(mTopComponent);
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            intent.addCategory(Intent.CATEGORY_HOME);
        }
        return intent;
    }
//根据intent,通过resolveActivityInfo函数向PackageManagerService查询Category类型为HOME的Activity的相关信息,这里我们假设只有系统自带的Launcher应用程序注册了HOME类型的Activity
 private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
        ActivityInfo ai = null;
        ComponentName comp = intent.getComponent();
        try {
            if (comp != null) {
                // Factory test.
                ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
            } else {
                ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
                        intent,
                        intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                        flags, userId);

                if (info != null) {
                    ai = info.activityInfo;
                }
            }
        } catch (RemoteException e) {
            // ignore
        }
        return ai;
    }
  • 上面方法就有点多了,主要作用就是获取要启动的Activity
  • 调用ActivityStarte#startHomeActivityLocked传递参数继续启动launcher
    • 创建一个Catery类型为HOME的Inent
    • 利用Intent去PackageManagerService里去找Catery为Home的Activiy 并收集相关的信息,例如报名
    • 获取到相关信息后,将包名设置给Intent,并指定当前Intent在新的栈中执行

ActivityStarter#startHomeActivityLocked;

void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
        mSupervisor.moveHomeStackTaskToTop(reason);
        mLastHomeActivityStartResult = startActivityLocked(null /*caller*/, 							         intent,null /*ephemeralIntent*/, null /*resolvedType*/,                                  aInfo, null /*rInfo*/, null /*voiceSession*/,
                         null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,                          0 /*requestCode*/, 0 /*callingPid*/,0 /*callingUid*/,
                         null /*callingPackage*/,
                         0 /*realCallingPid*/, 0 /*realCallingUid*/,
                         0 /*startFlags*/, null /*options*/, 
                         false /*ignoreTargetSecurity*/,
                         false /*componentSpecified*/,
                         mLastHomeActivityStartRecord /*outActivity*/,
                         null /*container*/, null /*inTask*/,
                         "startHomeActivity: " + reason);
        }
    }

2.调用 ActivityStarter#startActivityLocked 进一步操作

接下来的步骤就和Android启动(七)应用进程的启动过程2.2 调用startActivityLocked进一步操作` 大体相同了

  • 区别在于一个是启动Launcher一个是其他应用程序

  • 各方法因为启动launcher 和 其他应用程序参数不同,所以方法内执行代码会略有不同,但是从这开始方法调用栈就是相同的了

因此不在重复 大家可以去参考Android启动(七)应用进程的启动过程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值