该文章讲解下Launcher启动相关知识,并更正网上某些文章的错误点.

本篇为鸡生蛋系列第五篇文章, 也即最后篇, 终于可以结束该系列了。

[代码: Android 11]

[代码: Android 8.1]

startHomeActivityLocked()

搜网上资料, 好些文章说launcher启动是在ActivityManagerService.systemReady() --> startHomeActivityLocked()

时启动的, 那这个对不对呢? 这个其实对,也不对,(也可能是他们分析的版本太老了吧)。

说它不对我们后面点再说, 先简单看下这个流程代码。

AMS(ActivityManagerService) systemReady()是在SystemServer startOtherServices()时调用的, 其过程整理如下:frameworks/base/services/java/com/android/server/SystemServer.java

main(String[] args)

+ new SystemServer().run();

+ startBootstrapServices(t);

+ startCoreServices(t);

+ startOtherServices(t);

+ mActivityManagerService.systemReady(() -> {

......// callback参数会里启动system ui, 有需要的可关注下

startSystemUi(context, windowManagerF);

......

)

对于 < Android10的版本, AMS的systemReady()进一步通过 startHomeActivityLocked(), 好些文章认为在此就启动了launcherframeworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {

......

startHomeActivityLocked(currentUserId, "systemReady");

boolean startHomeActivityLocked(int userId, String reason) {

......

// home intent

Intent intent = getHomeIntent();

// 得到该intent应该启哪个应用

ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);

if (aInfo != null) {

......

// 启动该activity, 后面流程和应用启动流程差不多,就不说了

mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);

详细的代码讲解可网上搜下相关文章, 网上有很多,

好,

完!

可是...

事情真的完了吗?

我之前也一直以为是这样的, 我想着别人都写了一大堆这类文章,多我一个也没啥意思,所以就想用逆向分析的方法来看看,结果这一分析,发现有些不对的地方.

逆向分析

所谓逆向分析,就是我假设我不知道答案,也不太清楚framework咋玩的,从launcher的onCreate()入手,看能不能得到相同的结果.

所采用的方法呢,也很简单,也就是打印调用堆栈,然后看代码继续分析,继续打印调用堆栈....重复

具体的说,安卓java层常见的打印堆栈方法有如下几种:ThrowableLog.i(TAG, Log.getStackTraceString(new Throwable()));ExceptionException e = new Exception("testandroid this is a log");

e.printStackTrace();

也即简化为

new Exception("testandroid this is a log").printStackTrace();RuntimeExceptionRuntimeException callStack = new RuntimeException("callstack: ");

callStack.fillInStackTrace();

Log.e(TAG, "testandroid this is a log: ", callStack);

那我们就实战一把, 先在Launcher里加上log,

注意:

我实战用的代码为android8.1的源码, 因为我目前就只有该平台的开发机.

堆栈也不重要, 看下分析方法就行./home/atom/work/code/suiren_master/LINUX/android/packages/apps/Launcher3

@@ -350,6 +350,13 @@ public class Launcher extends BaseActivity

@Override

protected void onCreate(Bundle savedInstanceState) {

+ RuntimeException callStack = new RuntimeException("callstack: ");

+ callStack.fillInStackTrace();

+ Log.e(TAG,"testandroid this is a log: ", callStack);

打印出的堆栈如下:Launcher: testandroid this is a log:

Launcher: java.lang.RuntimeException: callstack:

Launcher: at com.android.launcher3.Launcher.onCreate(Launcher.java:354)

Launcher: at android.app.Activity.performCreate(Activity.java:7082)

Launcher: at android.app.Activity.performCreate(Activity.java:7073)

Launcher: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1215)

Launcher: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2737)

Launcher: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2862)

Launcher: at android.app.ActivityThread.-wrap11(Unknown Source:0)

Launcher: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1595)

Launcher: at android.os.Handler.dispatchMessage(Handler.java:106)

Launcher: at android.os.Looper.loop(Looper.java:164)

// ActivityThread.main()函数, 通过AMS startActivity()章节分析可知道其通过zyogote fork后会调用该函数

Launcher: at android.app.ActivityThread.main(ActivityThread.java:6524)

Launcher: at java.lang.reflect.Method.invoke(Native Method)

Launcher: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)

Launcher: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

结果加了第一个log,就发现了些问题,

问题1:

因为我们代码是有开机向导的,结果发现要开机向导结束后才调用Launcher的onCreate()

我在AMS startHomeActivityLocked()也加了log, systemReady()时确实是有调用到, 但是没有Launcher的onCreate(), 问题1之后才有

我先把逆向分析讲完再回头看这两问题

从上面堆栈看, 应用调到了ActivityThread.main(), 如果再沿着这个分析可能就很难了,这个就需要点背景知识了.

在分析AMS startActivity()时我们知道, 应用会通过zygoteProcess.start()请求zyogote fork应用,frameworks/base/core/java/android/os/Process.java

public static final ProcessStartResult start(final String processClass,

final String niceName,

int uid, int gid, int[] gids,

int runtimeFlags, int mountExternal,

int targetSdkVersion,

......) {

// 注意 processClass 为 "android.app.ActivityThread"

return zygoteProcess.start(processClass, niceName, uid, gid, gids,

runtimeFlags, mountExternal, targetSdkVersion, seInfo,

abi, instructionSet, appDataDir, invokeWith, zygoteArgs);

}

strat()会进一部调用startViaZygote(), 我们调加启动应用流程调用栈应该在如下地方frameworks/base/services/core/java/android/os/ZygoteProcess.java

private Process.ProcessStartResult startViaZygote(final String processClass,....

+ RuntimeException callStack = new RuntimeException("callstack: ");

+ callStack.fillInStackTrace();

// 将niceName打印出来方便看启动哪个应用

+ Log.e(LOG_TAG, "testandroid this is a log: " + processClass + " niceName:" + niceName + " ", callStack);

其堆栈如下// com.android.launcher3 启动

ZygoteProcess: testandroid this is a log: android.app.ActivityThread niceName:com.android.launcher3

ZygoteProcess: java.lang.RuntimeException: callstack:

ZygoteProcess: at android.os.ZygoteProcess.startViaZygote(ZygoteProcess.java:346)

ZygoteProcess: at android.os.ZygoteProcess.start(ZygoteProcess.java:208)

ZygoteProcess: at android.os.Process.start(Process.java:462)

ZygoteProcess: at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:4007)

ZygoteProcess: at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3829)

ZygoteProcess: at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3715)

ZygoteProcess: at com.android.server.am.ActivityStackSupervisor.startSpecificActivityLocked(ActivityStackSupervisor.java:1599)

ZygoteProcess: at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2755)

ZygoteProcess: at com.android.server.am.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:2268)

ZygoteProcess: at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:2102)

ZygoteProcess: at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1499)

ZygoteProcess: at com.android.server.am.ActivityStack.activityPausedLocked(ActivityStack.java:1426)

// activityPaused

ZygoteProcess: at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:7691)

// binder通信, 调用栈断了

ZygoteProcess: at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:317)

ZygoteProcess: at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2980)

这里onTransactd()是binder通信, 所以需要知道binder proxy侧谁调用该binder函数, 然后在那儿添加日志

通过搜代码,还好,就一个地方, 可以在该地方加上日志frameworks/base/core/java/android/app/ActivityThread.java

private void handlePauseActivity(IBinder token, boolean finished,....

......

// 调用activityPaused(), 可在此加上日志,

ActivityManager.getService().activityPaused(token);

因为中间有handler也会导致栈信息断, 对handler message这种导致的栈断只能分析代码看谁在sendMessage()给它了

具体过程了加的日志就不说了, 其流程为

schedulePauseActivity() --> sendMessage(PAUSE_ACTIVITY_FINISHING/PAUSE_ACTIVITY) --> handlePauseActivity() --> ActivityManager.getService().activityPaused(token);

进一步的堆栈如下:// 其是通过 ActivityStack.java schedulePauseActivity 调用到了

ActivityManager: testandroid ActivityStack.java schedulePauseActivity java.lang.Throwable

ActivityManager: at com.android.server.am.ActivityStack.startPausingLocked(ActivityStack.java:1359)

ActivityManager: at com.android.server.am.ActivityStack.finishActivityLocked(ActivityStack.java:3821)

ActivityManager: at com.android.server.am.ActivityStack.finishActivityLocked(ActivityStack.java:3763)

ActivityManager: at com.android.server.am.ActivityStack.requestFinishActivityLocked(ActivityStack.java:3611)

// 谁在调用finishActivity() ?

ActivityManager: at com.android.server.am.ActivityManagerService.finishActivity(ActivityManagerService.java:5283)

堆栈的最后为 finishActivity(), 那么谁在调用呢?

调用finishActivity()的地方也有好几个,可在各个地方加上代码, 最终是在 Activity.java finish() 调用的

代码如下:frameworks/base/core/java/android/app/Activity.java

private void finish(int finishTask) {

......

if (ActivityManager.getService()

.finishActivity(mToken, resultCode, resultData, finishTask)) {

堆栈如下:Activity.java finish()

System.err: java.lang.Exception: testandroid Activity.java finish

System.err: at android.app.Activity.finish(Activity.java:5562)

System.err: at android.app.Activity.finish(Activity.java:5600)

System.err: at com.android.settings.FallbackHome.maybeFinish(FallbackHome.java:129)

System.err: at com.android.settings.FallbackHome.-wrap0(Unknown Source:0)

System.err: at com.android.settings.FallbackHome$1.onReceive(FallbackHome.java:106)

至此, 我们终于看到了, 是在 FallbackHome onReceive() 时调用了finish(), 然后才把launcher启动起来.

那我们看下代码(分析看注释):packages/apps/Settings/src/com/android/settings/FallbackHome.java

protected void onCreate(Bundle savedInstanceState) {

......

// 注册了用户解锁的 receiver

registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));

// 注意这里的maybeFinish并没有调起launcher

maybeFinish();

}

private BroadcastReceiver mReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

// 接到用户解锁,然后调maybeFinish()

maybeFinish();

}

};

private void maybeFinish() {

// 用户是否解锁, 如果onCreate()-->maybeFinish()时如果用户没解锁则啥也不做

if (getSystemService(UserManager.class).isUserUnlocked()) {

final Intent homeIntent = new Intent(Intent.ACTION_MAIN)

.addCategory(Intent.CATEGORY_HOME);

......

Log.d(TAG, "User unlocked and real home found; let's go!");

getSystemService(PowerManager.class).userActivity(

SystemClock.uptimeMillis(), false);

// 调用finish结束自己activity

finish();

}

}

}

这时候事情进一步明了了,

FallbackHome onReceive() 接到用户解锁广播时调用了finish(),自己的activity退出时才把launcher启动

那 startHomeActivityLocked() 是不是在Launcher启动时就完全没作用呢?

发现有日志:

ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher} from uid 0

然后找到代码所在地方,通过打印堆栈发现其实是有调用的.ActivityManager: ActivityStarter.java testandroid this is a log:

ActivityManager: java.lang.RuntimeException: callstack:

ActivityManager: at com.android.server.am.ActivityStarter.startActivity(ActivityStarter.java:331)

ActivityManager: at com.android.server.am.ActivityStarter.startActivityLocked(ActivityStarter.java:283)

ActivityManager: at com.android.server.am.ActivityStarter.startHomeActivityLocked(ActivityStarter.java:655)

ActivityManager: at com.android.server.am.ActivityManagerService.startHomeActivityLocked(ActivityManagerService.java:4241)

ActivityManager: at com.android.server.am.ActivityStackSupervisor.resumeHomeStackTask(ActivityStackSupervisor.java:781)

ActivityManager: at com.android.server.am.ActivityStack.resumeTopActivityInNextFocusableStack(ActivityStack.java:2779)

ActivityManager: at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2326)

ActivityManager: at com.android.server.am.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:2268)

ActivityManager: at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:2107)

ActivityManager: at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:2091)

ActivityManager: at com.android.server.am.ActivityStack.finishCurrentActivityLocked(ActivityStack.java:3943)

ActivityManager: at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1458)

ActivityManager: at com.android.server.am.ActivityStack.activityPausedLocked(ActivityStack.java:1426)

ActivityManager: at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:7686)

ActivityManager: at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:317)

ActivityManager: at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2980)

Provision

让我们回到问题1因为我们代码是有开机向导的,结果发现要开机向导结束后才调用Launcher的onCreate()

Android默认的开机向导为 Provision, 其代码也很简单, 主要为

设置一些数据库值 --> 把自己disable, 之后home intent时就不会找到自己了 --> 结束自己packages/apps/Provision/src/com/android/provision/DefaultActivity.java

protected void onCreate(Bundle icicle) {

......

Settings.Global.putInt(getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1);

Settings.Secure.putInt(getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 1);

Settings.Secure.putInt(getContentResolver(), Settings.Secure.TV_USER_SETUP_COMPLETE, 1);

// remove this activity from the package manager.

// disable该activity

PackageManager pm = getPackageManager();

ComponentName name = new ComponentName(this, DefaultActivity.class);

pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,

PackageManager.DONT_KILL_APP);

// terminate the activity.

// 结束该activity

finish();

}

HOME intent优先级问题

AMS systemReady() --> startHomeActivityLocked() 时获取到的为 FallbackHomeboolean startHomeActivityLocked(int userId, String reason) {

// 获得home intent

Intent intent = getHomeIntent();

// 得到该intent应该启哪个应用

ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);

if (aInfo != null) {

......

mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);

日志(系统里还有别的响应home的activity, 这里就没列出了,主要看这三个):ActivityManager: startHomeActivityLocked ?? act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.settings/.FallbackHome

// 开机向导设置完之后DefaultActivity会禁用,之后启机不会再匹配上

ActivityManager: startHomeActivityLocked ?? act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.provision/.DefaultActivity

ActivityManager: startHomeActivityLocked ?? act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher

可是看了其优先级设置,packages/apps/Settings/AndroidManifest.xml

...... // FallbackHome 优先级 -1000

packages/apps/Provision/AndroidManifest.xml

......// DefaultActivity 优先级 3

FallbackHome 优先级 -1000, 为最小

DefaultActivity 优先级 3

Launcher3 没有设置

理论上来说,有开机向导时,应该 DefaultActivity 匹配上, 之后重启应该是 Launcher3 匹配上,

那么为啥systemReady()时为FallbackHome, 或者说为啥老是 FallbackHome 先匹配上?

按理来说其优先级最低,应该最后匹配上才对啊.

resolveActivityInfo()流程如下:resolveActivityInfo() / ActivityManagerService.java

+ AppGlobals.getPackageManager().resolveIntent()

+ resolveIntent() / PackageManagerService.java

+ resolveIntentInternal()

+ queryIntentActivitiesInternal() // 查询所有符合条件的activities

| + result = filterIfNotSystemUser(mActivities.queryIntent(.....))

| + super.queryIntent(....) / class ActivityIntentResolver

| + buildResolveList(....firstTypeCut, finalList, userId); / IntentResolver.java

+ chooseBestActivity() // 选择最好的那个

在上面流程中,会先查询出所有符合条件的activities, 然后选出最好的那个, 有需要的可以在这儿查看选取规则.

本以为是chooseBestActivity()时DefaultActivity/Launcher3不是最好的, 加上log确认原来在 queryIntentActivitiesInternal() 时最开始就只有 FallbackHome

直接启动

buildResolveList()之后可简单看看调查过程和注释, 因为代码老是变,也没多大意义, 主要的是提下后面的调查结果和发现了 直接启动 这么个对我来说的新东西.frameworks/base/services/core/java/com/android/server/IntentResolver.java

private void buildResolveList(Intent intent, FastImmutableArraySet categories,

boolean debug, boolean defaultOnly, String resolvedType, String scheme,

F[] src, List dest, int userId) {

......

match = filter.match(action, resolvedType, scheme, data, categories, TAG);

if (match >= 0) {

// 打开这里的日志发现其实最初时 FallbackHome DefaultActivity Launcher 都有match的

if (debug) Slog.v(TAG, " Filter matched! match=0x" +

Integer.toHexString(match) + " hasDefault="

+ filter.hasCategory(Intent.CATEGORY_DEFAULT));

if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {

// 但是后两者返回的为null

final R oneResult = newResult(filter, match, userId);

if (oneResult != null) {

// 如果不为null才加入到dest里

dest.add(oneResult);

newResult 对于activity intent来说实现在

PackageManagerService.java

......

final class ActivityIntentResolver

extends IntentResolver {

protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,

int match, int userId) {

if (!sUserManager.exists(userId)) return null;

// 这里返回为null, 因为DefaultActivity设置后会把自己禁用, 所以重启时他没匹配上倒也可以理解,

// 可是为啥起机后 Launcher 也在 FallbackHome 后匹配上呢? 可以继续调查

if (!mSettings.isEnabledAndMatchLPr(info.activity.info, mFlags, userId)) {

return null;

}

frameworks/base/services/core/java/com/android/server/pm/Settings.java

boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {

final PackageSetting ps = mPackages.get(componentInfo.packageName);

if (ps == null) return false;

final PackageUserState userState = ps.readUserState(userId);

// 这里反回false

return userState.isMatch(componentInfo, flags);

}

frameworks/base/core/java/android/content/pm/PackageUserState.java

public boolean isMatch(ComponentInfo componentInfo, int flags) {

final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();

final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;

if (!isAvailable(flags)

&& !(isSystemApp && matchUninstalled)) return false;

// Enable判断

if (!isEnabled(componentInfo, flags)) return false;

if ((flags & MATCH_SYSTEM_ONLY) != 0) {

if (!isSystemApp) {

return false;

}

}

final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)

&& !componentInfo.directBootAware;

final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)

&& componentInfo.directBootAware;

// 对Launcher来说, 这里起机时刚开始反回false, 之后返回true

return matchesUnaware || matchesAware;

}

看到最后 DIRECT_BOOT_UNAWARE DIRECT_BOOT_AWARE componentInfo.directBootAwar 这是啥呢?

这个其实就是对直接启动应用判断,

直接启动资料可看:

https://developer.android.goo...

简单说就是未解锁时可以运行的程序,比如说未解锁拍照.

FallbackHome 所在的设置是有支持直接启动, Launcher 不支持, 所以FallbackHome总是会先匹配, 解锁后Launcher才有机会匹配上.packages/apps/Settings/AndroidManifest.xml

...// FallbackHome 所在的设置支持直接启动

android:directBootAware="true">

总结对home intent的响应是有优先级的, 所以AMS systemReady()调用 start home时并不一定会启动launcher, 当其它优先级的home activity响应完后才有可能是 launcher

一般说来, launcher启动是在, settings FallbackHome 监听到解锁后调用finish() 结束自己时,才把launcher启动起来

因为 settings 支持 直接启动, launcher 不支持, 所以未解锁时launcher不会匹配到home intent.

一些home intent的优先级package activity优先级com.android.settings CryptKeeper10

com.android.provision DefaultActivity3

com.android.launcher3 Launcher默认

com.android.settings FallbackHome-1000Android 11 AMS systemRead() startHomeOnDisplay() 流程简单整理:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {

+ // goingCallback 回调, 这里会启动systemui

| if (goingCallback != null) goingCallback.run();

+ // start user

| mSystemServiceManager.startUser(t, currentUserId);

+ // 启动persistent应用

| startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);

+ // 启动所有屏的 Home,

| mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");

| // mAtmInternal为ActivityTaskManagerInternal类型,其最终实现在

| // ActivityTaskManagerService.java

+ // final class LocalService extends ActivityTaskManagerInternal

+ mRootWindowContainer.startHomeOnDisplay(...) / ActivityTaskManagerService.java

+ startHomeOnTaskDisplayArea(...) / RootWindowContainer.java

+ if (taskDisplayArea == getDefaultTaskDisplayArea()) {

| homeIntent = mService.getHomeIntent();

| // 得到默认屏home intent的activity

| aInfo = resolveHomeActivity(userId, homeIntent);

| } else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {

| // 得到第二个屏home intent的activity

| Pair info = resolveSecondaryHomeActivity(userId, taskDisplayArea);

+

+ mService.getActivityStartController().startHomeActivity(...)

+

| ActivityStartController.java

| void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason,

| TaskDisplayArea taskDisplayArea) {...

| // 多屏相关, 启动到哪个屏设置

| final int displayId = taskDisplayArea.getDisplayId();

| options.setLaunchDisplayId(displayId);

| options.setLaunchTaskDisplayArea(taskDisplayArea.mRemoteToken

| .toWindowContainerToken());

| ......

|

| mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)

| .setOutActivity(tmpOutRecord)

| .setCallingUid(0)

| .setActivityInfo(aInfo)

| .setActivityOptions(options.toBundle())

+ .execute();

java launcher在哪_HomeLauncher启动相关推荐

  1. java launcher在哪_JAVA Launcher简析

    JAVA Launcher简析 sun.misc.Launcher类是java的入口,在启动java应用的时候会首先创建Launcher类,创建Launcher类的时候回准备应用程序运行中需要的类加载 ...

  2. centos 开机启动java_Centos 7将java jar包自定义开机启动服务

    Centos 7将java jar包自定义开机启动服务 1. 先上 jar包的启动脚本 vim service.sh #!/bin/bash # 需要变更的参数 # 先查看java绝对路径:which ...

  3. Java线程:创建与启动

    Java线程:创建与启动 一.定义线程 1.扩展java.lang.Thread类. 此类中有个run()方法,应该注意其用法: public void run() 如果该线程是使用独立的 Runna ...

  4. Java静态编译技术:突破Java“冷启动”桎梏,实现启动性能“质”的飞跃

    自1996年诞生以来,Java语言长期在最受欢迎的编程语言排行榜中占据领先地位.除了语言本身的优秀特性之外,Java语言持续演进.不断发展也是它能够保持长盛不衰的重要原因. |Java市场份额不断下降 ...

  5. java djava_Java -Djava.ext.dirs启动的坑

    java以jar包形式启动启动 -Djava.ext.dirs=lib的作用 以bat形式启动项目,linux环境需要改变语法 ------------------------------ java ...

  6. java plug in错误_Eclipse启动失败 - 在安装BlackBerry Java Plug-in for Eclipse v1.3之后

    为了开发BlackBerry程序,下载了一个BlackBerry Java Plug-in for Eclipse v1.3.在安装完之后,得到了一个包含有BlackBerry开发插件的eclipse ...

  7. java machine 报错_Eclipse启动时报错:No java virtual machine

    第一次碰到这个问题,因为Eclipse是同学拷贝过来给我的. 错误提示如下: A java Runtime Environment (JRE) or Java Development Kit (JDK ...

  8. java Launcher源码_Launcher3源码浅析(5.1)--Launcher.java

    目录 前言 初始化 启动App/Widget 前言 第一次写博客,先来点废话唠叨唠叨.博客这玩意儿,还在上大学的时候老师就建议写一写了,可惜比较懒,一直没有动力去写.然后工作了两三年,现在突然发现以前 ...

  9. 启动Activity的流程(Launcher中点击图标启动)

    启动Activity一般有多种方式,常见的有三种: 在Launcher桌面点击app图标 调用startActivity启动一个Activity 命令am start启动 这三种方式在服务端的处理方式 ...

最新文章

  1. 路由器snmp配置_基于keepalived配置数据库主从实现高可用
  2. 解压文件出错解决方法(invalid compressed data--format violated)
  3. mongodb,redis,mysql 简要对比
  4. outguess秘钥加密--[BJDCTF 2nd]圣火昭昭-y1ng
  5. Struts2的核心文件
  6. Connection to @localhost failed. [08001] Could not create connection to database server. Attempt
  7. windows7计算机管理,windows7计算机管理
  8. python字典和集合对象可以进行索引操作_python字典和列表的高级应用
  9. 代码刚提交暂存区,组长突然要我把新增代码 Commit另一分支怎么办?
  10. 小白必须要会的Github操作 确定不进来看看?
  11. 广工十四届校赛 count 矩阵快速幂
  12. unity游戏开发毕设_请问自学Unity开发出一款游戏作为毕设大概要多久?
  13. CC00051.elasticsearch——|HadoopElasticSearch.V03|——|ELK.v03Logstash部署.V3|
  14. 软件工程(2019)结对编程第一次作业
  15. creo2.0+VS2010采用protoolkit二次开发环境配置(64位win7)
  16. 土地利用程度综合指数计算/argis教程
  17. 一种高效、安全的Dota全图新思路
  18. iOS上线APP在App Store地址
  19. 用C语言读取.txt文本,并保存在二维数组中
  20. linux dmesg命令参数及用法详解

热门文章

  1. [[概率论与数理统计-2]:随机函数、概率、概率函数、概率分布函数
  2. 就打一个小补丁?Win 10一周年更新版亮相
  3. openwrt开发--ILI9341屏幕显示开发
  4. solr5使用suggest模块实现搜索联想
  5. 6.2 jmeter基础—元件执行顺序
  6. 飞歌G7导航安装激Poweramp(安卓)
  7. [渝粤教育] 西南科技大学 公共关系学 在线考试复习资料(1)
  8. 领导者如何增强说服力
  9. python编辑视频字符化_Python 视频转字符画 - 进阶
  10. 2021 PAT甲级秋季题解