ADB 原理
大家都知道 adb shell 后可以执行很多命令,这里我们主要是介绍 adb shell 进入后是如何执行那些代码命令的,这里我们就以 “am start ” 命令来说。绝大多的命令代码都是在 frameworks/base/cmds 这个目录下的,am 命令也不例外。
am 的开始是由一段脚步执行的。同时am 底下的 Android.bp 会将相关代码编译成一个 am.jar Java可执行库。
# frameworks/base/cmds/am/am
#!/system/bin/sh
if [ "$1" != "instrument" ] ; then
cmd activity "$@"
else
base=/system
export CLASSPATH=$base/framework/am.jar
exec app_process $base/bin com.android.commands.am.Am "$@"
fi
am.jar 库的入口函数就在 am.jar 下
// frameworks/base/cmds/am/src/com/android/commands/am/Am.java
public static void main(String[] args) {
(new Am()).run(args);
}
紧接着看看他的run方法, 由于Am 是继承BaseCommand.java ,没重新 run ,重写了onRun
// frameworks/base/core/java/com/android/internal/os/BaseCommand.java
/**
* Call to run the command.
*/
public void run(String[] args) {
if (args.length < 1) {
onShowUsage(System.out);
return;
}
mRawArgs = args;
mArgs.init(null, null, null, null, args, null, 0);
try {
onRun(); // 下一步入口
} catch (IllegalArgumentException e) {
onShowUsage(System.err);
System.err.println();
System.err.println("Error: " + e.getMessage());
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(1);
}
}
回到我们之前Am.java 方法,找到大家熟悉的姿势。
// frameworks/base/cmds/am/src/com/android/commands/am/Am.java
@Override
public void onRun() throws Exception {
mAm = ActivityManager.getService();// 记着这里
if (mAm == null) {
System.err.println(NO_SYSTEM_ERROR_CODE);
throw new AndroidException("Can't connect to activity manager; is the system running?");
}
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
if (mPm == null) {
System.err.println(NO_SYSTEM_ERROR_CODE);
throw new AndroidException("Can't connect to package manager; is the system running?");
}
String op = nextArgRequired();
if (op.equals("instrument")) {
runInstrument(); //这里是通过 Instrument启动 读者自行分析。
} else {
runAmCmd(getRawArgs());// 这里是通过正常startactivity 启动。
}
}
// 细品一些这个runAmCmd, 你好好品品。
void runAmCmd(String[] args) throws AndroidException {
final MyShellCallback cb = new MyShellCallback();
try {
mAm.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
args, cb, new ResultReceiver(null) { }); //终于走到了常规套路。
} catch (RemoteException e) {
System.err.println(NO_SYSTEM_ERROR_CODE);
throw new AndroidException("Can't call activity manager; is the system running?");
} finally {
cb.mActive = false;
}
}
中间商 Binder
//frameworks/base/core/java/android/os/Binder.java
public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
@Nullable FileDescriptor err,
@NonNull String[] args, @Nullable ShellCallback callback,
@NonNull ResultReceiver resultReceiver) throws RemoteException {
// 看 AMS
onShellCommand(in, out, err, args, callback, resultReceiver);
}
辗转来到 ActivityManagerService
//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
(new ActivityManagerShellCommand(this, false)).exec(
this, in, out, err, args, callback, resultReceiver);
}
ActivityManagerShellCommand 是继承自 ShellCommand类,这个 exec 是在 ShellCommand 里的,主要用来初始化一些参数和环境
// frameworks/base/core/java/android/os/ShellCommand.java
public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
String cmd;
int start;
if (args != null && args.length > 0) {
cmd = args[0];
start = 1;
} else {
cmd = null;
start = 0;
}
init(target, in, out, err, args, callback, start);
mCmd = cmd;
mResultReceiver = resultReceiver;
if (DEBUG) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget, here);
Slog.d(TAG, "Calling uid=" + Binder.getCallingUid()
+ " pid=" + Binder.getCallingPid() + " ShellCallback=" + getShellCallback());
}
int res = -1;
try {
res = onCommand(mCmd); // 回掉主要接口函数
if (DEBUG) Slog.d(TAG, "Executed command " + mCmd + " on " + mTarget);
} catch (SecurityException e) {
PrintWriter eout = getErrPrintWriter();
eout.println("Security exception: " + e.getMessage());
eout.println();
e.printStackTrace(eout);
} catch (Throwable e) {
// Unlike usual calls, in this case if an exception gets thrown
// back to us we want to print it back in to the dump data, since
// that is where the caller expects all interesting information to
// go.
PrintWriter eout = getErrPrintWriter();
eout.println();
eout.println("Exception occurred while executing:");
e.printStackTrace(eout);
} finally {
if (DEBUG) Slog.d(TAG, "Flushing output streams on " + mTarget);
if (mOutPrintWriter != null) {
mOutPrintWriter.flush();
}
if (mErrPrintWriter != null) {
mErrPrintWriter.flush();
}
if (DEBUG) Slog.d(TAG, "Sending command result on " + mTarget);
if (mResultReceiver != null) {
mResultReceiver.send(res, null);
}
}
if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget);
return res;
}
圆规正转让我们来看一下 onCommand
所有 am 的命令接在此了。
//frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@Override
public int onCommand(String cmd) {
if (cmd == null) {
return handleDefaultCommands(cmd);
}
final PrintWriter pw = getOutPrintWriter();
try {
switch (cmd) {
// 这就是使用‘am start’ 和 ‘am start-activity’ 是相同结果了。
case "start":
case "start-activity":
return runStartActivity(pw);
case "startservice":
case "start-service":
return runStartService(pw, false);
case "startforegroundservice":
case "startfgservice":
case "start-foreground-service":
case "start-fg-service":
return runStartService(pw, true);
case "stopservice":
case "stop-service":
return runStopService(pw);
case "broadcast":
return runSendBroadcast(pw);
case "instrument":
getOutPrintWriter().println("Error: must be invoked through 'am instrument'.");
return -1;
case "trace-ipc":
return runTraceIpc(pw);
case "profile":
return runProfile(pw);
case "dumpheap":
return runDumpHeap(pw);
case "set-debug-app":
return runSetDebugApp(pw);
case "set-agent-app":
return runSetAgentApp(pw);
case "clear-debug-app":
return runClearDebugApp(pw);
case "set-watch-heap":
return runSetWatchHeap(pw);
case "clear-watch-heap":
return runClearWatchHeap(pw);
case "bug-report":
return runBugReport(pw);
case "force-stop":
return runForceStop(pw);
case "crash":
return runCrash(pw);
case "kill":
return runKill(pw);
case "kill-all":
return runKillAll(pw);
case "make-uid-idle":
return runMakeIdle(pw);
case "monitor":
return runMonitor(pw);
case "watch-uids":
return runWatchUids(pw);
case "hang":
return runHang(pw);
case "restart":
return runRestart(pw);
case "idle-maintenance":
return runIdleMaintenance(pw);
case "screen-compat":
return runScreenCompat(pw);
case "package-importance":
return runPackageImportance(pw);
case "to-uri":
return runToUri(pw, 0);
case "to-intent-uri":
return runToUri(pw, Intent.URI_INTENT_SCHEME);
case "to-app-uri":
return runToUri(pw, Intent.URI_ANDROID_APP_SCHEME);
case "switch-user":
return runSwitchUser(pw);
case "get-current-user":
return runGetCurrentUser(pw);
case "start-user":
return runStartUser(pw);
case "unlock-user":
return runUnlockUser(pw);
case "stop-user":
return runStopUser(pw);
case "is-user-stopped":
return runIsUserStopped(pw);
case "get-started-user-state":
return runGetStartedUserState(pw);
case "track-associations":
return runTrackAssociations(pw);
case "untrack-associations":
return runUntrackAssociations(pw);
case "get-uid-state":
return getUidState(pw);
case "get-config":
return runGetConfig(pw);
case "suppress-resize-config-changes":
return runSuppressResizeConfigChanges(pw);
case "set-inactive":
return runSetInactive(pw);
case "get-inactive":
return runGetInactive(pw);
case "set-standby-bucket":
return runSetStandbyBucket(pw);
case "get-standby-bucket":
return runGetStandbyBucket(pw);
case "send-trim-memory":
return runSendTrimMemory(pw);
case "display":
return runDisplay(pw);
case "stack":
return runStack(pw);
case "task":
return runTask(pw);
case "write":
return runWrite(pw);
case "attach-agent":
return runAttachAgent(pw);
case "supports-multiwindow":
return runSupportsMultiwindow(pw);
case "supports-split-screen-multi-window":
return runSupportsSplitScreenMultiwindow(pw);
case "update-appinfo":
return runUpdateApplicationInfo(pw);
case "no-home-screen":
return runNoHomeScreen(pw);
case "wait-for-broadcast-idle":
return runWaitForBroadcastIdle(pw);
case "compat":
return runCompat(pw);
default:
return handleDefaultCommands(cmd);
}
} catch (RemoteException e) {
pw.println("Remote exception: " + e);
}
return -1;
}
其实分析到这里就可以结束了,耐不住好奇继续看吧
比较长的方法
int runStartActivity(PrintWriter pw) throws RemoteException {
Intent intent;
try {
// 构建 Intent 这里面有玄机
intent = makeIntent(UserHandle.USER_CURRENT);
} catch (URISyntaxException e) {
throw new RuntimeException(e.getMessage(), e);
}
if (mUserId == UserHandle.USER_ALL) {
getErrPrintWriter().println("Error: Can't start service with user 'all'");
return 1;
}
String mimeType = intent.getType();
if (mimeType == null && intent.getData() != null
&& "content".equals(intent.getData().getScheme())) {
mimeType = mInterface.getProviderMimeType(intent.getData(), mUserId);
}
do {
if (mStopOption) {
String packageName;
if (intent.getComponent() != null) {
packageName = intent.getComponent().getPackageName();
} else {
// queryIntentActivities does not convert user id, so we convert it here first
int userIdForQuery = mInternal.mUserController.handleIncomingUser(
Binder.getCallingPid(), Binder.getCallingUid(), mUserId, false,
ALLOW_NON_FULL, "ActivityManagerShellCommand", null);
List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType, 0,
userIdForQuery).getList();
if (activities == null || activities.size() <= 0) {
getErrPrintWriter().println("Error: Intent does not match any activities: "
+ intent);
return 1;
} else if (activities.size() > 1) {
getErrPrintWriter().println(
"Error: Intent matches multiple activities; can't stop: "
+ intent);
return 1;
}
packageName = activities.get(0).activityInfo.packageName;
}
pw.println("Stopping: " + packageName);
pw.flush();
mInterface.forceStopPackage(packageName, mUserId);
try {
Thread.sleep(250);
} catch (InterruptedException e) {
}
}
ProfilerInfo profilerInfo = null;
if (mProfileFile != null || mAgent != null) {
ParcelFileDescriptor fd = null;
if (mProfileFile != null) {
fd = openFileForSystem(mProfileFile, "w");
if (fd == null) {
return 1;
}
}
profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop,
mStreaming, mAgent, mAttachAgentDuringBind);
}
pw.println("Starting: " + intent);
pw.flush();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
WaitResult result = null;
int res;
final long startTime = SystemClock.uptimeMillis();
// 构建启动项,不会启动activity 可以在这里学习,细品
ActivityOptions options = null;
if (mDisplayId != INVALID_DISPLAY) {
options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(mDisplayId);
}
if (mWindowingMode != WINDOWING_MODE_UNDEFINED) {
if (options == null) {
options = ActivityOptions.makeBasic();
}
options.setLaunchWindowingMode(mWindowingMode);
}
if (mActivityType != ACTIVITY_TYPE_UNDEFINED) {
if (options == null) {
options = ActivityOptions.makeBasic();
}
options.setLaunchActivityType(mActivityType);
}
if (mTaskId != INVALID_TASK_ID) {
if (options == null) {
options = ActivityOptions.makeBasic();
}
options.setLaunchTaskId(mTaskId);
if (mIsTaskOverlay) {
options.setTaskOverlay(true, true /* canResume */);
}
}
if (mIsLockTask) {
if (options == null) {
options = ActivityOptions.makeBasic();
}
options.setLockTaskEnabled(true);
}
// 开始启动了,3 、2、1 点火。
if (mWaitOption) {
result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, intent, mimeType,
null, null, 0, mStartFlags, profilerInfo,
options != null ? options.toBundle() : null, mUserId);
res = result.result;
} else {
res = mInternal.startActivityAsUser(null, SHELL_PACKAGE_NAME, intent, mimeType,
null, null, 0, mStartFlags, profilerInfo,
options != null ? options.toBundle() : null, mUserId);
}
final long endTime = SystemClock.uptimeMillis();
PrintWriter out = mWaitOption ? pw : getErrPrintWriter();
boolean launched = false;
// 检查结果,汇到情况。
switch (res) {
case ActivityManager.START_SUCCESS:
launched = true;
break;
case ActivityManager.START_SWITCHES_CANCELED:
launched = true;
out.println(
"Warning: Activity not started because the "
+ " current activity is being kept for the user.");
break;
case ActivityManager.START_DELIVERED_TO_TOP:
launched = true;
out.println(
"Warning: Activity not started, intent has "
+ "been delivered to currently running "
+ "top-most instance.");
break;
case ActivityManager.START_RETURN_INTENT_TO_CALLER:
launched = true;
out.println(
"Warning: Activity not started because intent "
+ "should be handled by the caller");
break;
case ActivityManager.START_TASK_TO_FRONT:
launched = true;
out.println(
"Warning: Activity not started, its current "
+ "task has been brought to the front");
break;
case ActivityManager.START_INTENT_NOT_RESOLVED:
out.println(
"Error: Activity not started, unable to "
+ "resolve " + intent.toString());
break;
case ActivityManager.START_CLASS_NOT_FOUND:
out.println(NO_CLASS_ERROR_CODE);
out.println("Error: Activity class " +
intent.getComponent().toShortString()
+ " does not exist.");
break;
case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
out.println(
"Error: Activity not started, you requested to "
+ "both forward and receive its result");
break;
case ActivityManager.START_PERMISSION_DENIED:
out.println(
"Error: Activity not started, you do not "
+ "have permission to access it.");
break;
case ActivityManager.START_NOT_VOICE_COMPATIBLE:
out.println(
"Error: Activity not started, voice control not allowed for: "
+ intent);
break;
case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY:
out.println(
"Error: Not allowed to start background user activity"
+ " that shouldn't be displayed for all users.");
break;
default:
out.println(
"Error: Activity not started, unknown error code " + res);
break;
}
out.flush();
if (mWaitOption && launched) {
if (result == null) {
result = new WaitResult();
result.who = intent.getComponent();
}
pw.println("Status: " + (result.timeout ? "timeout" : "ok"));
pw.println("LaunchState: " + launchStateToString(result.launchState));
if (result.who != null) {
pw.println("Activity: " + result.who.flattenToShortString());
}
if (result.totalTime >= 0) {
pw.println("TotalTime: " + result.totalTime);
}
pw.println("WaitTime: " + (endTime-startTime));
pw.println("Complete");
pw.flush();
}
mRepeat--;
if (mRepeat > 0) {
mTaskInterface.unhandledBack();
}
} while (mRepeat > 0);
return 0;
}