• Android framework服务命令行工具框架 - Android13


    1、framework服务命令行工具简介

    这里强调 “framework服务” ,主要就是bin命令模拟 framework服务 相关的查询和功能,如am\pm\input等;其实质就是 Android 提供了大多数常见的 Unix 命令行工具,说白了就是bin执行程序 。而 framework服务 命令行工具现在一般就是cmdbin执行程序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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    2.3 cmd命令

    1. cmd
      在这里插入图片描述

    2. cmd -l 列出SM中注册的服务
      在这里插入图片描述

    3. 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    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));
       //... ... ... ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161

    4、简易时序图

    在这里插入图片描述

  • 相关阅读:
    DNS/ICMP协议/NAT技术
    【常识】回调函数
    vue手搓悬浮在线客服按钮
    MPLS 初见
    【java】java线程池
    杨氏干涉实验
    k8s二进制安装
    【深度学习】 Python 和 NumPy 系列教程(廿六):Matplotlib详解:3、多子图和布局:subplots()函数
    【Pytorch with fastai】第 3 章 :数据伦理
    【深圳大学算法设计与分析】 实验六 最大流应用问题 FF -> EK -> Dinic
  • 原文地址:https://blog.csdn.net/qq_23452385/article/details/134087671