【Android12】Android Framework系列--AMS启动Activity分析

news2024/11/23 21:08:24

AMS启动Activity分析

通过ActivityManagerService(AMS)提供的方法,可以启动指定的Activity。比如Launcher中点击应用图标后,调用AMS的startActivity函数启动应用。
AMS提供的服务通过IActivityManager.aidl文件定义。

// frameworks/base/core/java/android/app/IActivityManager.aidl
package android.app;
// 省略
/**
 * System private API for talking with the activity manager service.  This
 * provides calls from the application back to the activity manager.
 *
 * {@hide}
 */
interface IActivityManager {
	// 省略
    /** @deprecated Use {@link #startActivityWithFeature} instead */
    @UnsupportedAppUsage(maxTargetSdk=29, publicAlternatives="Use {@link android.content.Context#startActivity(android.content.Intent)} instead")
    int startActivity(in IApplicationThread caller, in String callingPackage, in Intent intent,
            in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode,
            int flags, in ProfilerInfo profilerInfo, in Bundle options);
    int startActivityWithFeature(in IApplicationThread caller, in String callingPackage,
            in String callingFeatureId, in Intent intent, in String resolvedType,
            in IBinder resultTo, in String resultWho, int requestCode, int flags,
            in ProfilerInfo profilerInfo, in Bundle options);
	// 省略
}

代码版本是Android12。分析一下从应用侧(比如Launcher)调用startActivity启动另一个应用的流程。
在这里插入图片描述

startActivity源码分析

应用侧可以通过context的startActivity函数调用AMS。比如下述例子。

Intent intent = new Intent();
// 启动com.linduo.test这个Package中的  MainActivity
intent.setComponent(new ComponentName("com.linduo.test", "com.linduo.test.MainActivity"));
context.startActivity(intent);

context是abstract的类,其实现在ContextImpl中。

// frameworks/base/core/java/android/content/ContextWrapper.java
public class ContextWrapper extends Context {
}

// frameworks/base/core/java/android/app/ContextImpl.java
class ContextImpl extends Context {
@Override
public void startActivity(Intent intent) {
	warnIfCallingFromSystemProcess();
	startActivity(intent, null);
}

@Override
public void startActivity(Intent intent, Bundle options) {
	warnIfCallingFromSystemProcess();

	// Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
	// generally not allowed, except if the caller specifies the task id the activity should
	// be launched in. A bug was existed between N and O-MR1 which allowed this to work. We
	// maintain this for backwards compatibility.
	final int targetSdkVersion = getApplicationInfo().targetSdkVersion;

	if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
			&& (targetSdkVersion < Build.VERSION_CODES.N
					|| targetSdkVersion >= Build.VERSION_CODES.P)
			&& (options == null
					|| ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
		throw new AndroidRuntimeException(
				"Calling startActivity() from outside of an Activity "
						+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
						+ " Is this really what you want?");
	}
	mMainThread.getInstrumentation().execStartActivity(
			getOuterContext(), mMainThread.getApplicationThread(), null,
			(Activity) null, intent, -1, options);
}
}

ContextImpl通过mMainThread(ActivityThread类型)得到了Instrumentation对象,调用Instrumentation的execStartActivity函数。execStartActivity函数中,如果开启了Activity监听模式,会通知监听者onStartActivity,然后调用ActivityTaskManagerService的startActivity函数启动Activity。最后检查启动的结果,如果启动失败抛出对应的异常。
onStartActivity的监听,可以使用Instrumentation.addMonitor方式,具体内容可以查看Instrumentation.java

// frameworks/base/core/java/android/app/Instrumentation.java
@UnsupportedAppUsage
public ActivityResult execStartActivity(
		Context who, IBinder contextThread, IBinder token, Activity target,
		Intent intent, int requestCode, Bundle options) {
	IApplicationThread whoThread = (IApplicationThread) contextThread;
	Uri referrer = target != null ? target.onProvideReferrer() : null;
	if (referrer != null) {
		intent.putExtra(Intent.EXTRA_REFERRER, referrer);
	}
	if (mActivityMonitors != null) {
		// 如果开启了监听,会给监听者通过 onStartActivity
		synchronized (mSync) {
			final int N = mActivityMonitors.size();
			for (int i=0; i<N; i++) {
				final ActivityMonitor am = mActivityMonitors.get(i);
				ActivityResult result = null;
				if (am.ignoreMatchingSpecificIntents()) {
					result = am.onStartActivity(intent);
				}
				if (result != null) {
					am.mHits++;
					return result;
				} else if (am.match(who, null, intent)) {
					am.mHits++;
					if (am.isBlocking()) {
						return requestCode >= 0 ? am.getResult() : null;
					}
					break;
				}
			}
		}
	}
	try {
		intent.migrateExtraStreamToClipData(who);
		intent.prepareToLeaveProcess(who);
		// 调用ActivityTaskManagerService( AMS中提供的服务)
		int result = ActivityTaskManager.getService().startActivity(whoThread,
				who.getOpPackageName(), who.getAttributionTag(), intent,
				intent.resolveTypeIfNeeded(who.getContentResolver()), token,
				target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
		// 检查启动的结果,如果失败会throw异常。
		checkStartActivityResult(result, intent);
	} catch (RemoteException e) {
		throw new RuntimeException("Failure from system", e);
	}
	return null;
}

ActivityTaskManagerService继承了IActivityTaskManager.Stub,属于AMS提供的服务。在其startActivity函数中,会调用startActivityAsUser,判断package与UID是否相符、是否为Isolated模式的应用、并检查用户权限(源码中可以看出系统用户权限非常大,所以为了安全要慎用系统用户权限),最终调用ActivityStarterexecute启动Activity。

// frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
		String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
		String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
		Bundle bOptions) {
	// 调用startActivityAsUser
	return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
			resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
			UserHandle.getCallingUserId());
}

@Override
public int startActivityAsUser(IApplicationThread caller, String callingPackage,
		String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
		String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
		Bundle bOptions, int userId) {
	// 调用startActivityAsUser,validateIncomingUser为true
	return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
			resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
			true /*validateIncomingUser*/);
}

private int startActivityAsUser(IApplicationThread caller, String callingPackage,
		@Nullable String callingFeatureId, Intent intent, String resolvedType,
		IBinder resultTo, String resultWho, int requestCode, int startFlags,
		ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
	// 判断调用的package和UID相符
	assertPackageMatchesCallingUid(callingPackage);
	// 禁止来自Isolated模式应用的调用
	enforceNotIsolatedCaller("startActivityAsUser");

	// 检测用户权限。这个函数中,可以看出系统用户权限非常大(感兴趣的可以看一下)
	userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
			Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

	// 通过ActivityStartController,取得ActivityStarter,设置好系列参数后调用execute
	// TODO: Switch to user app stacks here.
	return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
			.setCaller(caller)
			.setCallingPackage(callingPackage)
			.setCallingFeatureId(callingFeatureId)
			.setResolvedType(resolvedType)
			.setResultTo(resultTo)
			.setResultWho(resultWho)
			.setRequestCode(requestCode)
			.setStartFlags(startFlags)
			.setProfilerInfo(profilerInfo)
			.setActivityOptions(bOptions)
			.setUserId(userId)
			.execute();

}

ActivityStarter的execute函数中,再次进行了一些检查,比如是否存在文件句柄泄露(Intent)、config是否要变更,并调用了executeRequest函数。

// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
int execute() {
	try {
		// Refuse possible leaked file descriptors
		if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {
			throw new IllegalArgumentException("File descriptors passed in Intent");
		}

		final LaunchingState launchingState;
		synchronized (mService.mGlobalLock) {
			final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);
			final int callingUid = mRequest.realCallingUid == Request.DEFAULT_REAL_CALLING_UID
					?  Binder.getCallingUid() : mRequest.realCallingUid;
			launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
					mRequest.intent, caller, callingUid);
		}

		// If the caller hasn't already resolved the activity, we're willing
		// to do so here. If the caller is already holding the WM lock here,
		// and we need to check dynamic Uri permissions, then we're forced
		// to assume those permissions are denied to avoid deadlocking.
		if (mRequest.activityInfo == null) {
			mRequest.resolveActivity(mSupervisor);
		}

		// Add checkpoint for this shutdown or reboot attempt, so we can record the original
		// intent action and package name.
		if (mRequest.intent != null) {
			String intentAction = mRequest.intent.getAction();
			String callingPackage = mRequest.callingPackage;
			if (intentAction != null && callingPackage != null
					&& (Intent.ACTION_REQUEST_SHUTDOWN.equals(intentAction)
							|| Intent.ACTION_SHUTDOWN.equals(intentAction)
							|| Intent.ACTION_REBOOT.equals(intentAction))) {
				ShutdownCheckPoints.recordCheckPoint(intentAction, callingPackage, null);
			}
		}

		int res;
		synchronized (mService.mGlobalLock) {
			final boolean globalConfigWillChange = mRequest.globalConfig != null
					&& mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
			// 获取当前处于Top且Focus的RootTask
			final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
			if (rootTask != null) {
				// RookTask非空,更新一下ConfigChange的Flag。
				rootTask.mConfigWillChange = globalConfigWillChange;
			}
			ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config "
					+ "will change = %b", globalConfigWillChange);

			final long origId = Binder.clearCallingIdentity();

			res = resolveToHeavyWeightSwitcherIfNeeded();
			if (res != START_SUCCESS) {
				return res;
			}
			// 这个函数中,会创建ActivityRecord,并启动Activity
			res = executeRequest(mRequest);
			// 后面的函数,主要是Config的变更。如果有变化会给config变化的通知。
			// 以及结果的检查。
			Binder.restoreCallingIdentity(origId);

			if (globalConfigWillChange) {
				// If the caller also wants to switch to a new configuration, do so now.
				// This allows a clean switch, as we are waiting for the current activity
				// to pause (so we will not destroy it), and have not yet started the
				// next activity.
				mService.mAmInternal.enforceCallingPermission(
						android.Manifest.permission.CHANGE_CONFIGURATION,
						"updateConfiguration()");
				if (rootTask != null) {
					rootTask.mConfigWillChange = false;
				}
				ProtoLog.v(WM_DEBUG_CONFIGURATION,
							"Updating to new configuration after starting activity.");

				mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
			}

			// The original options may have additional info about metrics. The mOptions is not
			// used here because it may be cleared in setTargetRootTaskIfNeeded.
			final ActivityOptions originalOptions = mRequest.activityOptions != null
					? mRequest.activityOptions.getOriginalOptions() : null;
			// If the new record is the one that started, a new activity has created.
			final boolean newActivityCreated = mStartActivity == mLastStartActivityRecord;
			// Notify ActivityMetricsLogger that the activity has launched.
			// ActivityMetricsLogger will then wait for the windows to be drawn and populate
			// WaitResult.
			mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
					newActivityCreated, mLastStartActivityRecord, originalOptions);
			if (mRequest.waitResult != null) {
				mRequest.waitResult.result = res;
				res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord,
						launchingState);
			}
			return getExternalResult(res);
		}
	} finally {
		onExecutionComplete();
	}
}

ActivityStarter的executeRequest比较长,下面省略一部分内容。根据其注释内容“Executing activity start request and starts the journey of starting an activity”也可以看出,在这里处理了activity启动的请求。函数中,进行了权限检查,包括判断了是否为Home应用,创建了ActivityRecord记录这次启动为最后一次启动的Activity,然后调用startActivityUnchecked启动应用。

// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
/**
 * Executing activity start request and starts the journey of starting an activity. Here
 * begins with performing several preliminary checks. The normally activity launch flow will
 * go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
 */
private int executeRequest(Request request) {

	// 检查启动 权限
	boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
			requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
			request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord,
			resultRootTask);
	abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
			callingPid, resolvedType, aInfo.applicationInfo);
	abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
			callingPackage);

	boolean restrictedBgActivity = false;
	if (!abort) {
		try {
			Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
					"shouldAbortBackgroundActivityStart");
			// 判断是否可以启动Activity.
			// 这里也会判断是否为Home应用,如果是Home应用的可以启动。如果不是,还要进行其他判断。
			restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
					callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
					request.originatingPendingIntent, request.allowBackgroundActivityStart,
					intent);
		} finally {
			Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
		}
	}
	
	// 创建ActivityRecord
	final ActivityRecord r = new ActivityRecord.Builder(mService)
			.setCaller(callerApp)
			.setLaunchedFromPid(callingPid)
			.setLaunchedFromUid(callingUid)
			.setLaunchedFromPackage(callingPackage)
			.setLaunchedFromFeature(callingFeatureId)
			.setIntent(intent)
			.setResolvedType(resolvedType)
			.setActivityInfo(aInfo)
			.setConfiguration(mService.getGlobalConfiguration())
			.setResultTo(resultRecord)
			.setResultWho(resultWho)
			.setRequestCode(requestCode)
			.setComponentSpecified(request.componentSpecified)
			.setRootVoiceInteraction(voiceSession != null)
			.setActivityOptions(checkedOptions)
			.setSourceRecord(sourceRecord)
			.build();
	// 记录为最后一次启动的Activity
	mLastStartActivityRecord = r;
	// 调用startActivityUnchecked,启动Activity
	mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
			request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
			restrictedBgActivity, intentGrants);

	if (request.outActivity != null) {
		request.outActivity[0] = mLastStartActivityRecord;
	}

	return mLastStartActivityResult;
}

ActivityStarter的startActivityUnchecked函数会调用startActivityInner函数,在这个函数中获取加载Activity的RootTask加载Activity,并调用RootWindowContainer的resumeFocusedTasksTopActivities函数fork出一个进程来运行Activity。


// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java

/**
 * Start an activity while most of preliminary checks has been done and caller has been
 * confirmed that holds necessary permissions to do so.
 * Here also ensures that the starting activity is removed if the start wasn't successful.
 */
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
			IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
			int startFlags, boolean doResume, ActivityOptions options, Task inTask,
			boolean restrictedBgActivity, NeededUriGrants intentGrants) {
	// 省略
	try {
		mService.deferWindowLayout();
		Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
		// 调用startActivityInner
		result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
				startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
	} finally {
		// 省略
	}

	postStartActivityProcessing(r, result, startedActivityRootTask);

	return result;
}


/**
 * Start an activity and determine if the activity should be adding to the top of an existing
 * task or delivered new intent to an existing activity. Also manipulating the activity task
 * onto requested or valid root-task/display.
 *
 * Note: This method should only be called from {@link #startActivityUnchecked}.
 */

// TODO(b/152429287): Make it easier to exercise code paths through startActivityInner
@VisibleForTesting
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
		IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
		int startFlags, boolean doResume, ActivityOptions options, Task inTask,
		boolean restrictedBgActivity, NeededUriGrants intentGrants) {
	// 省略
	if (mTargetRootTask == null) {
		// 获取目标RootTask
		mTargetRootTask = getLaunchRootTask(mStartActivity, mLaunchFlags, targetTask, mOptions);
	}
	// 调用RootTask,startActivity(细节可以顺着这个函数看)
	mTargetRootTask.startActivityLocked(mStartActivity,
			topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
			mKeepCurTransition, mOptions, sourceRecord);
			
	// mDoResume为Ture
	if (mDoResume) {
		if (!mTargetRootTask.isTopActivityFocusable()
				|| (topTaskActivity != null && topTaskActivity.isTaskOverlay()
				&& mStartActivity != topTaskActivity)) {
			// 省略
		} else {
			// If the target root-task was not previously focusable (previous top running
			// activity on that root-task was not visible) then any prior calls to move the
			// root-task to the will not update the focused root-task.  If starting the new
			// activity now allows the task root-task to be focusable, then ensure that we
			// now update the focused root-task accordingly.
			if (mTargetRootTask.isTopActivityFocusable()
					&& !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
				mTargetRootTask.moveToFront("startActivityInner");
			}
			mRootWindowContainer.resumeFocusedTasksTopActivities(
					mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
		}
	}
	mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);

	// Update the recent tasks list immediately when the activity starts
	mSupervisor.mRecentTasks.add(mStartActivity.getTask());
	mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
			mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask);

	return START_SUCCESS;
}

启动的Activity如果是另一个应用,Android会fork出一个进程来加载Activity。那么是在哪里进行的fork?
在ActivityStarter的handleStartResult中,会进行fork进程操作(调用Process.start实现)

// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
/**
 * Start an activity while most of preliminary checks has been done and caller has been
 * confirmed that holds necessary permissions to do so.
 * Here also ensures that the starting activity is removed if the start wasn't successful.
 */
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
		IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
		int startFlags, boolean doResume, ActivityOptions options, Task inTask,
		TaskFragment inTaskFragment, boolean restrictedBgActivity,
		NeededUriGrants intentGrants) {
	int result = START_CANCELED;
	final Task startedActivityRootTask;

	// Create a transition now to record the original intent of actions taken within
	// startActivityInner. Otherwise, logic in startActivityInner could start a different
	// transition based on a sub-action.
	// Only do the create here (and defer requestStart) since startActivityInner might abort.
	final TransitionController transitionController = r.mTransitionController;
	Transition newTransition = (!transitionController.isCollecting()
			&& transitionController.getTransitionPlayer() != null)
			? transitionController.createTransition(TRANSIT_OPEN) : null;
	RemoteTransition remoteTransition = r.takeRemoteTransition();
	if (newTransition != null && remoteTransition != null) {
		newTransition.setRemoteTransition(remoteTransition);
	}
	transitionController.collect(r);
	try {
		mService.deferWindowLayout();
		Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
		result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
				startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity,
				intentGrants);
	} finally {
		Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
		// 这里会fork出一个进程(调用RootWindowContainer.ensureVisibilityAndConfig),最终调用Process.start
		startedActivityRootTask = handleStartResult(r, options, result, newTransition,
				remoteTransition);
		mService.continueWindowLayout();
	}
	postStartActivityProcessing(r, result, startedActivityRootTask);

	return result;
}

下面是调用的堆栈(Android13输出的,大概流程一样),感兴趣的可以依照堆栈看源码.

ActivityTaskManager:     at com.android.server.wm.ActivityTaskManagerService.startProcessAsync(ActivityTaskManagerService.java:4683)
ActivityTaskManager:     at com.android.server.wm.ActivityTaskSupervisor.startSpecificActivity(ActivityTaskSupervisor.java:1013)
ActivityTaskManager:     at com.android.server.wm.EnsureActivitiesVisibleHelper.makeVisibleAndRestartIfNeeded(EnsureActivitiesVisibleHelper.java:265)
ActivityTaskManager:     at com.android.server.wm.EnsureActivitiesVisibleHelper.setActivityVisibilityState(EnsureActivitiesVisibleHelper.java:191)
ActivityTaskManager:     at com.android.server.wm.EnsureActivitiesVisibleHelper.process(EnsureActivitiesVisibleHelper.java:139)
ActivityTaskManager:     at com.android.server.wm.TaskFragment.updateActivityVisibilities(TaskFragment.java:985)
ActivityTaskManager:     at com.android.server.wm.Task.lambda$ensureActivitiesVisible$15(Task.java:4866)
ActivityTaskManager:     at com.android.server.wm.Task$$ExternalSyntheticLambda20.accept(Unknown Source:10)
ActivityTaskManager:     at com.android.server.wm.Task.forAllLeafTasks(Task.java:3185)
ActivityTaskManager:     at com.android.server.wm.Task.ensureActivitiesVisible(Task.java:4865)
ActivityTaskManager:     at com.android.server.wm.DisplayContent.lambda$ensureActivitiesVisible$46(DisplayContent.java:6000)
ActivityTaskManager:     at com.android.server.wm.DisplayContent$$ExternalSyntheticLambda17.accept(Unknown Source:10)
ActivityTaskManager:     at com.android.server.wm.Task.forAllRootTasks(Task.java:3197)
ActivityTaskManager:     at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:1806)
ActivityTaskManager:     at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:1806)
ActivityTaskManager:     at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:1806)
ActivityTaskManager:     at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:1806)
ActivityTaskManager:     at com.android.server.wm.WindowContainer.forAllRootTasks(WindowContainer.java:1799)
ActivityTaskManager:     at com.android.server.wm.DisplayContent.ensureActivitiesVisible(DisplayContent.java:5999)
ActivityTaskManager:     at com.android.server.wm.RootWindowContainer.ensureActivitiesVisible(RootWindowContainer.java:2075)
ActivityTaskManager:     at com.android.server.wm.RootWindowContainer.ensureVisibilityAndConfig(RootWindowContainer.java:1876)
ActivityTaskManager:     at com.android.server.wm.ActivityStarter.handleStartResult(ActivityStarter.java:1669)
ActivityTaskManager:     at com.android.server.wm.ActivityStarter.startActivityUnchecked(ActivityStarter.java:1598)
ActivityTaskManager:     at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:1185)
ActivityTaskManager:     at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:672)
ActivityTaskManager:     at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1243)
ActivityTaskManager:     at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1215)
ActivityTaskManager:     at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:969)
ActivityTaskManager:     at com.android.server.wm.ActivityTaskManagerService.onTransact(ActivityTaskManagerService.java:5152)
ActivityTaskManager:     at android.os.Binder.execTransactInternal(Binder.java:1179)
ActivityTaskManager:     at android.os.Binder.execTransact(Binder.java:1143)
ActivityTaskManager: java.lang.Throwable

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1310745.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AI底层逻辑】——数学与机器学习:优雅的智慧之舞

目录 “宝藏网站” 聊聊数学 “华尔兹” “智慧之舞” 后续的章节我们将迎来新的篇章&#xff0c;新的切入点探索AI的奥秘&#xff0c;通过揭示高数、矩阵、概率论等数学知识与机器学习的关系来深入理解AI的奥秘&#xff01; “宝藏网站” 开头先给大家上几个宝藏网站&am…

【离散数学】——期末刷题题库(欧拉图和哈密顿图)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

java中,用函数对象表示策略

简而言之&#xff0c;函数指针的主要用途就是实现策略(Strategy)模式。 Java没有提供函数指针&#xff0c;但是可以用对象引用实现相同的功能。调用对象上的方法通常是执行该对象上某项操作。 在Java中&#xff0c;使用函数对象&#xff08;Function Object&#xff09;表示策…

《数据结构、算法与应用C++语言描述》-机器调度-最长处理时间(LPT)

机器调度 完整可编译运行代码见&#xff1a;Github::Data-Structures-Algorithms-and-Applications/_28LongestProcessingTime 问题描述 一个工厂具有 m台一模一样的机器。我们有n 个任务需要处理。设作业i的处理时间为 t i t_i ti​&#xff0c;这个时间包括把作业放入机器…

Amazon Aurora Limitless Database:数据库管理的全新境界

授权说明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 在当今数亿用户、PB级数据和数百万交易的业务环境中&#xff0c;数…

12.14_黑马数据结构与算法笔记Java

目录 120 二叉搜索树 min max 121 二叉搜索树 put 122 二叉搜索树 前任后任1 123 二叉搜索树 前任后任2 124 二叉搜索树 删除1 125 二叉搜索树 删除2 126 二叉搜索树 删除3 127 二叉搜索树 删除 递归1 128 二叉搜索树 删除 递归2 129 二叉搜索树 范围查询 130 二叉搜…

KUKA机器人如何隐藏程序或程序段?

KUKA机器人如何隐藏程序或程序段? 如下图所示,新建一个示例程序进行说明, 如下图所示,如果红框中的动作指令不想让别人看到,想隐藏起来,如何做到? 如下图所示,在想要隐藏的程序或程序段的前后,分别添加 ;fold 和 endfold指令(这里要注意是英文状态下的输入法), 如…

国标GB28181安防监控系统/磁盘阵列EasyCVR(V.3.4)新亮点:免保活功能

TSINGSEE青犀近日发布了EasyCVR安防管理平台的V.3.4版本&#xff0c;其中一大亮点就是很多朋友都在咨询的“免保活”功能&#xff0c;那么&#xff0c;什么是“免保活”功能&#xff1f;又该如何配置呢&#xff1f; 在EasyCVR平台有个【按需直播】按钮&#xff0c;顾名思义&…

如何部署Portainer容器管理工具+cpolar内网穿透实现公网访问管理界面

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 本文主要介绍如何本地安装Portainer并结合内网穿透工具实现任意浏览器远程访问管理界面。Portainer 是一个轻量级…

大象elephant目标检测数据集VOC+YOLO格式2300张

大象是长鼻目象科的哺乳动物&#xff0c;有两个属&#xff0c;是世界上最大的陆生动物。其像柱子一样的四肢和宽厚的脚掌可以稳稳支撑住庞大的身体。巨大的头上长有蒲扇状的大耳朵和长且有弹性的鼻子。象耳上有丰富的血管&#xff0c;可以有效散热。鼻子和上唇合而为一的象鼻由…

YB9225是一种固定工作频率的高效率电流模式升压转换器。

YB9225B 1.2 MHz。峰值5A 电流&#xff0c;升压转换器 概述 &#xff1a; YB9225是一种固定工作频率的高效率电流模式升压转换器。YB9225集成了一个非常低的 Rds-on NMOSFTET&#xff0c;以减少功率损耗和实现高效率。最高效率可达93% 。功率 MOSFET 的峰值电流限制在5 A。1.…

网站使用CDN后无法获取用户真实IP的解决方法

宝塔或Nginx环境 如果你使用的宝塔或Nginx&#xff0c;可以在宝塔面板或Nginx中&#xff0c;找到配置文件增加如下代码后&#xff0c;重载配置或者重启 Nginx 即可&#xff1a; #CDN获取真实ip set_real_ip_from 0.0.0.0/0; real_ip_header X-Forwarded-For; PHP语言函数方法…

36、什么是池化算法

池化算法也是 CNN 网络中非常常见的算法。 池化这一算法理解起来比较简单,从名字中或许可以看到一些东西:从一个像素池子中选取一些有代表性的像素出来。 常见的池化有最大池化和平均池化。最大池化就是从像素池子中选取最大值出来,而平均池化就是从像素池子中选取平均值出…

HTML---初识CSS

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.CSS概念 CSS是层叠样式表&#xff08;Cascading Style Sheets&#xff09;的缩写。它是一种用于描述HTML文档外观样式的标记语言。通过CSS&#xff0c;开发者可以在不改变HTML标记结构的情况…

机器学习 | 机器学习基础知识

一、机器学习是什么 计算机从数据中学习规律并改善自身进行预测的过程。 二、数据集 1、最常用的公开数据集 2、结构化数据与非结构化数据 三、任务地图 1、分类任务 Classification 已知样本特征判断样本类别二分类、多分类、多标签分类 二分类&#xff1a;垃圾邮件分类、图像…

【数据结构入门精讲 | 第一篇】打开数据结构之门

数据结构与算法是计算机科学中的核心概念&#xff0c;也与现实生活如算法岗息息相关。鉴于全网数据结构文章良莠不齐且集成度不高&#xff0c;故开设本专栏&#xff0c;为初学者提供指引。 目录 基本概念数据结构为何面世算法基本数据类型抽象数据类型使用抽象数据类型的好处 数…

利用Pytorch预训练模型进行图像分类

Use Pre-trained models for Image Classification. # This post is rectified on the base of https://learnopencv.com/pytorch-for-beginners-image-classification-using-pre-trained-models/# And we have re-orginaized the code script.预训练模型(Pre-trained models)…

【SpringBoot】进阶之自定义starter(一起了解自定义starter的魅力)

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《SpringBoot开发》。&#x1f3af;&#x1f3af;…

解决设备能耗管理问题,易点易动来帮忙!

设备能耗管理是现代企业可持续发展的重要环节&#xff0c;然而&#xff0c;许多企业在设备能耗管理方面面临一系列问题&#xff1a; 能耗数据收集困难&#xff1a;企业需要监控和管理大量设备的能耗情况&#xff0c;但传统的手动方式收集能耗数据耗时耗力&#xff0c;无法实时获…

Python中的TesserOCR:文字识别的全方位指南

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 文字识别在图像处理领域中起到了至关重要的作用&#xff0c;而TesserOCR&#xff08;Tesseract OCR的Python封装&#xff09;为开发者提供了一个强大的工具&#xff0c;使得文字识别变得更加便捷。本文将通过详细…