首先执行 adb shell svc bluetooth help
看一下
~/debuglogger/mobilelog/APLog_2021_1118_173806__1$ adb shell svc bluetooth help
Control Bluetooth service
usage: svc bluetooth [enable|disable]
Turn Bluetooth on or off.
然后根据 Control Bluetooth service
字符串查找相关文件
~/projects/MTK_R_6580_2/alps/frameworks$ grep "Control Bluetooth service" ./ -r
frameworks/base/cmds/svc/src/com/android/commands/svc/BluetoothCommand.java: return "Control Bluetooth service";
frameworks/base/cmds/svc/src/com/android/commands/svc/BluetoothCommand.java
public class BluetoothCommand extends Svc.Command {
public BluetoothCommand() {
super("bluetooth");
}
@Override
public String shortHelp() {
return "Control Bluetooth service";
}
@Override
public String longHelp() {
return shortHelp() + "\n"
+ "\n"
+ "usage: svc bluetooth [enable|disable]\n"
+ " Turn Bluetooth on or off.\n\n";
}
@Override
public void run(String[] args) {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter == null) {
System.err.println("Got a null BluetoothAdapter, is the system running?");
return;
}
if (args.length == 2 && "enable".equals(args[1])) {
adapter.enable();
} else if (args.length == 2 && "disable".equals(args[1])) {
adapter.disable();
} else {
System.err.println(longHelp());
}
}
}
从上面的代码中看到run()会根据传入的参数执行不同的操作,传入 enable 会执行 adapter.enable();
方法打开蓝牙,传入 disable 会执行 adapter.disable();
方法关闭蓝牙。
再看看其他的方法,找找有用的信息
public BluetoothCommand() {
super("bluetooth"); // 这个应该就是 adb shell svc bluetooth 中的 bluetooth
}
shortHelp() 和 longHelp() 应该就是命令的帮助信息模板方法
@Override
public String shortHelp() {
return "Control Bluetooth service";
}
@Override
public String longHelp() {
return shortHelp() + "\n"
+ "\n"
+ "usage: svc bluetooth [enable|disable]\n"
+ " Turn Bluetooth on or off.\n\n";
}
这个类相当简单,是否只要继承Command.Svc 这个类就可以实现类似的功能?再找找系统中是否还有其他继承 Command.Svc 类的子类。搜索结果如下:
~/projects/MTK_R_6580_2/alps/frameworks$ grep "Svc.Command" ./ -r
frameworks/base/cmds/svc/src/com/android/commands/svc/PowerCommand.java:public class PowerCommand extends Svc.Command {
frameworks/base/cmds/svc/src/com/android/commands/svc/NfcCommand.java:public class NfcCommand extends Svc.Command {
frameworks/base/cmds/svc/src/com/android/commands/svc/BluetoothCommand.java:public class BluetoothCommand extends Svc.Command {
frameworks/base/cmds/svc/src/com/android/commands/svc/SystemServerCommand.java:public class SystemServerCommand extends Svc.Command {
frameworks/base/cmds/svc/src/com/android/commands/svc/UsbCommand.java:public class UsbCommand extends Svc.Command {
果然找到一堆支持svc的命令,分析一波,用法如下:
NFC
public String longHelp() {
return shortHelp() + "\n"
+ "\n"
+ "usage: svc nfc [enable|disable]\n"
+ " Turn NFC on or off.\n\n";
}
Bluetooth
public String longHelp() {
return shortHelp() + "\n"
+ "\n"
+ "usage: svc bluetooth [enable|disable]\n"
+ " Turn Bluetooth on or off.\n\n";
}
USB
public String longHelp() {
return shortHelp() + "\n"
+ "\n"
+ "usage: svc usb setFunctions [function]\n"
+ " Set the current usb function. If function is blank, sets to charging.\n"
+ " svc usb setScreenUnlockedFunctions [function]\n"
+ " Sets the functions which, if the device was charging, become current on"
+ "screen unlock. If function is blank, turn off this feature.\n"
+ " svc usb getFunctions\n"
+ " Gets the list of currently enabled functions\n"
+ " svc usb resetUsbGadget\n"
+ " Reset usb gadget\n\n"
+ "possible values of [function] are any of 'mtp', 'ptp', 'rndis', 'midi'\n";
}
system-server
public String longHelp() {
return shortHelp() + "\n"
+ "\n"
+ "usage: system-server wait-for-crash\n"
+ " Wait until the system server process crashes.\n\n";
}
power
public String longHelp() {
return shortHelp() + "\n"
+ "\n"
+ "usage: svc power stayon [true|false|usb|ac|wireless]\n"
+ " Set the 'keep awake while plugged in' setting.\n"
+ " svc power reboot [reason]\n"
+ " Perform a runtime shutdown and reboot device with specified reason.\n"
+ " svc power shutdown\n"
+ " Perform a runtime shutdown and power off the device.\n"
+ " svc power forcesuspend [t]\n"
+ " Force the system into suspend, ignoring all wakelocks.\n"
+ " t - Number of milliseconds to wait before issuing force-suspend.\n"
+ " Helps with devices that can't suspend while plugged in.\n"
+ " Defaults to " + FORCE_SUSPEND_DELAY_DEFAULT_MILLIS + ".\n"
+ " When using a delay, you must use the nohup shell modifier:\n"
+ " 'adb shell nohup svc power forcesuspend [time]'\n"
+ " Use caution; this is dangerous. It puts the device to sleep\n"
+ " immediately without giving apps or the system an opportunity to\n"
+ " save their state.\n";
}
再解析一波大佬frameworks/base/cmds/svc/src/com/android/commands/svc/Svc.java
public class Svc {
public static abstract class Command {
private String mName;
public Command(String name) {
mName = name;
}
public String name() {
return mName;
}
public abstract String shortHelp(); // should fit on one short line
public abstract String longHelp(); // take as much space as you need, 75 col max
public abstract void run(String[] args); // run the command
}
public static void main(String[] args) {
if (args.length >= 1) {
Command c = lookupCommand(args[0]);
if (c != null) {
c.run(args);
return;
}
}
COMMAND_HELP.run(args);
}
private static Command lookupCommand(String name) {
final int N = COMMANDS.length;
for (int i=0; i<N; i++) {
Command c = COMMANDS[i];
if (c.name().equals(name)) {
return c;
}
}
return null;
}
public static final Command COMMAND_HELP = new Command("help") {
public String shortHelp() {
return "Show information about the subcommands";
}
public String longHelp() {
return shortHelp();
}
public void run(String[] args) {
if (args.length == 2) {
Command c = lookupCommand(args[1]);
if (c != null) {
System.err.println(c.longHelp());
return;
}
}
System.err.println("Available commands:");
final int N = COMMANDS.length;
int maxlen = 0;
for (int i=0; i<N; i++) {
Command c = COMMANDS[i];
int len = c.name().length();
if (maxlen < len) {
maxlen = len;
}
}
String format = " %-" + maxlen + "s %s";
for (int i=0; i<N; i++) {
Command c = COMMANDS[i];
System.err.println(String.format(format, c.name(), c.shortHelp())); //help命令就是把COMMANDS中的所有命令遍历一遍,并且打印 shortHelp() 方法中的信息
}
}
};
public static final Command[] COMMANDS = new Command[] {
COMMAND_HELP,
new PowerCommand(),
// `svc wifi` has been migrated to WifiShellCommand
new UsbCommand(),
new NfcCommand(),
new BluetoothCommand(),
new SystemServerCommand(),
};
}
这个就是一个典型的Java程序,从main()方法开始执行,如果svc后面的参数不为空就执行
public static void main(String[] args) {
if (args.length >= 1) {
Command c = lookupCommand(args[0]); //如果svc后面有参数,就从COMMANDS数组中看是否支持这个参数
if (c != null) {
c.run(args); //如果支持就执行
return;
}
}
COMMAND_HELP.run(args);//如果svc后面的参数为空,或者COMMANDS中没有这个参数就执行help命令
}
adb shell svc
结果显示如下
Available commands:
help Show information about the subcommands
power Control the power manager
usb Control Usb state
nfc Control NFC functions
bluetooth Control Bluetooth service
system-server System server process related command
adb shell which svc
adb shell which svc
/system/bin/svc
adb shell ls /system/bin/svc -al
-rwxr-xr-x 1 root shell 1068 2021-11-19 11:42 /system/bin/svc
adb shell cat /system/bin/svc
#!/system/bin/sh
# `svc wifi` has been migrated to WifiShellCommand,
# simply perform translation to `cmd wifi set-wifi-enabled` here.
if [ "x$1" == "xwifi" ]; then
# `cmd wifi` by convention uses enabled/disabled
# instead of enable/disable
if [ "x$2" == "xenable" ]; then
exec cmd wifi set-wifi-enabled enabled
elif [ "x$2" == "xdisable" ]; then
exec cmd wifi set-wifi-enabled disabled
else
echo "Control the Wi-Fi manager"
echo ""
echo "usage: svc wifi [enable|disable]"
echo " Turn Wi-Fi on or off."
echo ""
fi
exit 1
fi
if [ "x$1" == "xdata" ]; then
if [ "x$2" == "xenable" ]; then
exec cmd phone data enable
elif [ "x$2" == "xdisable" ]; then
exec cmd phone data disable
else
echo "Enable/Disable Mobile Data Connectivity"
echo ""
echo "usage: svc data [enable|disable]"
echo ""
fi
exit 1
fi
export CLASSPATH=/system/framework/svc.jar
exec app_process /system/bin com.android.commands.svc.Svc "$@"
/system/bin/svc
文件就是 frameworks/base/cmds/svc/svc
frameworks/base/cmds/svc/svc
这个文件是在哪里编进去的呢?
frameworks/base/cmds/svc/Android.bp
文件中只有java文件的编译方法,生成的是jar包,out/target/product/k80_bsp/system/framework/svc.jar
java_binary {
name: "svc",
wrapper: "svc",
srcs: ["**/*.java"],
}
在 ./out/soong/Android-full_k80_bsp.mk
下找到了 svc 对应的module代码,但又是在哪里生成这个文件的呢?
include $(CLEAR_VARS)
LOCAL_PATH := frameworks/base/cmds/svc
LOCAL_MODULE := svc
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_PREBUILT_MODULE_FILE := frameworks/base/cmds/svc/svc
LOCAL_MODULE_TARGET_ARCH := arm
LOCAL_NOTICE_FILE := frameworks/base/cmds/svc/NOTICE
LOCAL_STRIP_MODULE := false
include $(BUILD_PREBUILT)
$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)
jar_installed_module :=