Android framework服务命令行工具框架 - Android13
Android framework服务命令行工具框架 - Android13
- 1、framework服务命令行工具简介
- 2、cmd 执行程序
- 2.1 目录和Android.bp
- 2.2 cmdMain 执行入口
- 2.3 cmd命令
- 3、am命令工具,实质脚本执行cmd activity
- 3.1 sh脚本
- 3.2 activity服务注册
- 3.3 onShellCommand执行
- 4、简易时序图
1、framework服务命令行工具简介
这里强调 “framework服务” ,主要就是bin命令模拟 framework服务 相关的查询和功能,如am\pm\input等;其实质就是
Android 提供了大多数常见的 Unix 命令行工具,说白了就是bin执行程序
。而 framework服务 命令行工具现在一般就是cmd
bin执行程序Binder获取对应服务,通过IBinder::shellCommand
调用对应服务的onShellCommand
。
2、cmd 执行程序
2.1 目录和Android.bp
frameworks/native/cmds/cmd/Android.bp
frameworks/native/cmds/cmd/cmd.cpp
2.2 cmdMain 执行入口
DEBUG
:默认关闭#define DEBUG 0
serviceName
:SM中注册的binder服务对应的名称,如ACTIVITY_SERVICE = "activity"
(ActivityManagerService)IBinder::shellCommand(service, in, out, err, args, cb, result)
:执行到对应服务onShellCommand
frameworks/native/cmds/cmd/cmd.cpp
int cmdMain(const std::vector<std::string_view>& argv, TextOutput& outputLog, TextOutput& errorLog,
int in, int out, int err, RunMode runMode) {
sp<ProcessState> proc = ProcessState::self();
proc->startThreadPool();
#if DEBUG
ALOGD("cmd: starting");
#endif
sp<IServiceManager> sm = defaultServiceManager();
if (runMode == RunMode::kStandalone) {
fflush(stdout);
}
if (sm == nullptr) {
ALOGW("Unable to get default service manager!");
errorLog << "cmd: Unable to get default service manager!" << endl;
return 20;
}
int argc = argv.size();
if (argc == 0) {
errorLog << "cmd: No service specified; use -l to list all running services. Use -w to start and wait for a service." << endl;
return 20;
}
if ((argc == 1) && (argv[0] == "-l")) {
Vector<String16> services = sm->listServices();
services.sort(sort_func);
outputLog << "Currently running services:" << endl;
for (size_t i=0; i<services.size(); i++) {
sp<IBinder> service = sm->checkService(services[i]);
if (service != nullptr) {
outputLog << " " << services[i] << endl;
}
}
return 0;
}
bool waitForService = ((argc > 1) && (argv[0] == "-w"));
int serviceIdx = (waitForService) ? 1 : 0;
const auto cmd = argv[serviceIdx];
Vector<String16> args;
String16 serviceName = String16(cmd.data(), cmd.size());
for (int i = serviceIdx + 1; i < argc; i++) {
args.add(String16(argv[i].data(), argv[i].size()));
}
sp<IBinder> service;
if(waitForService) {
service = sm->waitForService(serviceName);
} else {
service = sm->checkService(serviceName);
}
if (service == nullptr) {
if (runMode == RunMode::kStandalone) {
ALOGW("Can't find service %.*s", static_cast<int>(cmd.size()), cmd.data());
}
errorLog << "cmd: Can't find service: " << cmd << endl;
return 20;
}
sp<MyShellCallback> cb = new MyShellCallback(errorLog);
sp<MyResultReceiver> result = new MyResultReceiver();
#if DEBUG
ALOGD("cmd: Invoking %.*s in=%d, out=%d, err=%d",
static_cast<int>(cmd.size()), cmd.data(), in, out, err);
#endif
// TODO: block until a result is returned to MyResultReceiver.
status_t error = IBinder::shellCommand(service, in, out, err, args, cb, result);
if (error < 0) {
const char* errstr;
switch (error) {
case BAD_TYPE: errstr = "Bad type"; break;
case FAILED_TRANSACTION: errstr = "Failed transaction"; break;
case FDS_NOT_ALLOWED: errstr = "File descriptors not allowed"; break;
case UNEXPECTED_NULL: errstr = "Unexpected null"; break;
default: errstr = strerror(-error); break;
}
if (runMode == RunMode::kStandalone) {
ALOGW("Failure calling service %.*s: %s (%d)", static_cast<int>(cmd.size()), cmd.data(),
errstr, -error);
}
outputLog << "cmd: Failure calling service " << cmd << ": " << errstr << " (" << (-error)
<< ")" << endl;
return error;
}
cb->mActive = false;
status_t res = result->waitForResult();
#if DEBUG
ALOGD("result=%d", (int)res);
#endif
return res;
}
2.3 cmd命令
-
cmd
-
cmd -l
列出SM中注册的服务
-
cmd activity
3、am命令工具,实质脚本执行cmd activity
3.1 sh脚本
这里am工具为例。Android 提供了大多数常见的 Unix 命令行工具,查看可用工具的列表:
adb shell ls /system/bin
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
3.2 activity服务注册
activity
服务就是ActivityManagerService
注册的Context.ACTIVITY_SERVICE
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_HIGH);
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
mAppProfiler.setCpuInfoService();
ServiceManager.addService("permission", new PermissionController(this));
ServiceManager.addService("processinfo", new ProcessInfoService(this));
ServiceManager.addService("cacheinfo", new CacheBinder(this));
//... ... ... ...
}
3.3 onShellCommand执行
ActivityManagerShellCommand
专门处理am
相关命令,这里具体功能不展开细说。
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);
}
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) {
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 "compact":
return runCompact(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 "clear-exit-info":
return runClearExitInfo(pw);
case "bug-report":
return runBugReport(pw);
case "force-stop":
return runForceStop(pw);
case "stop-app":
return runStopApp(pw);
case "fgs-notification-rate-limit":
return runFgsNotificationRateLimit(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);
case "refresh-settings-cache":
return runRefreshSettingsCache();
case "memory-factor":
return runMemoryFactor(pw);
case "service-restart-backoff":
return runServiceRestartBackoff(pw);
case "get-isolated-pids":
return runGetIsolatedProcesses(pw);
case "set-stop-user-on-switch":
return runSetStopUserOnSwitch(pw);
case "set-bg-abusive-uids":
return runSetBgAbusiveUids(pw);
case "list-bg-exemptions-config":
return runListBgExemptionsConfig(pw);
default:
return handleDefaultCommands(cmd);
}
} catch (RemoteException e) {
pw.println("Remote exception: " + e);
}
return -1;
}