之前在使用adb时,用过很多命令 比如adb install 等最后是调用了 pm相关命令,和java service相关的命令都在Framework/base/cmds目录下,今天我们来讲下service命令,这个命令可以和任何一个注册到servicemanager的service进行通信。代码在Framework/native/cmds/service下。
一、命令
我们先看下help介绍:
Usage: service [-h|-?]
service list
service check SERVICE
service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...
Options:
i32: Write the 32-bit integer N into the send parcel.
i64: Write the 64-bit integer N into the send parcel.
f: Write the 32-bit single-precision number N into the send parcel.
d: Write the 64-bit double-precision number N into the send parcel.
s16: Write the UTF-16 string STR into the send parcel.
service list列出所有的service,call service就是向相关service传递命令,各个参数的类型可以用i32等表示。
例子:
比如命令
service call phone 2 s16 "123"
就是调用了下面函数 s16代表String类型 "123"就是参数。
void call(String number);
二、源码
我们来看下service的源码:
int main(int argc, char* const argv[])
{
sp<IServiceManager> sm = defaultServiceManager();//获取servicemanager的binder
fflush(stdout);
if (sm == NULL) {
aerr << "service: Unable to get default service manager!" << endl;
return 20;
}
bool wantsUsage = false;
int result = 0;
while (1) {
int ic = getopt(argc, argv, "h?");
if (ic < 0)
break;
switch (ic) {
case 'h':
case '?':
wantsUsage = true;
break;
default:
aerr << "service: Unknown option -" << ic << endl;
wantsUsage = true;
result = 10;
break;
}
}
if (optind >= argc) {
wantsUsage = true;
} else if (!wantsUsage) {
if (strcmp(argv[optind], "check") == 0) {//check命令
optind++;
if (optind < argc) {
sp<IBinder> service = sm->checkService(String16(argv[optind]));
aout << "Service " << argv[optind] <<
(service == NULL ? ": not found" : ": found") << endl;
} else {
aerr << "service: No service specified for check" << endl;
wantsUsage = true;
result = 10;
}
}
else if (strcmp(argv[optind], "list") == 0) {//list命令
Vector<String16> services = sm->listServices();
aout << "Found " << services.size() << " services:" << endl;
for (unsigned i = 0; i < services.size(); i++) {
String16 name = services[i];
sp<IBinder> service = sm->checkService(name);
aout << i
<< "\t" << good_old_string(name)
<< ": [" << good_old_string(get_interface_name(service)) << "]"
<< endl;
}
} else if (strcmp(argv[optind], "call") == 0) {//call命令
optind++;
if (optind+1 < argc) {
int serviceArg = optind;
sp<IBinder> service = sm->checkService(String16(argv[optind++]));//获取service的binder
String16 ifName = get_interface_name(service);
int32_t code = atoi(argv[optind++]);
if (service != NULL && ifName.size() > 0) {//下面把数据分装在Parcel中
Parcel data, reply;
// the interface name is first
data.writeInterfaceToken(ifName);
// then the rest of the call arguments
while (optind < argc) {
if (strcmp(argv[optind], "i32") == 0) {
optind++;
if (optind >= argc) {
aerr << "service: no integer supplied for 'i32'" << endl;
wantsUsage = true;
result = 10;
break;
}
data.writeInt32(atoi(argv[optind++]));
} else if (strcmp(argv[optind], "i64") == 0) {
optind++;
if (optind >= argc) {
aerr << "service: no integer supplied for 'i64'" << endl;
wantsUsage = true;
result = 10;
break;
}
data.writeInt64(atoll(argv[optind++]));
} else if (strcmp(argv[optind], "s16") == 0) {
optind++;
if (optind >= argc) {
aerr << "service: no string supplied for 's16'" << endl;
wantsUsage = true;
result = 10;
break;
}
data.writeString16(String16(argv[optind++]));
} else if (strcmp(argv[optind], "f") == 0) {
optind++;
if (optind >= argc) {
aerr << "service: no number supplied for 'f'" << endl;
wantsUsage = true;
result = 10;
break;
}
data.writeFloat(atof(argv[optind++]));
} else if (strcmp(argv[optind], "d") == 0) {
optind++;
if (optind >= argc) {
aerr << "service: no number supplied for 'd'" << endl;
wantsUsage = true;
result = 10;
break;
}
data.writeDouble(atof(argv[optind++]));
} else if (strcmp(argv[optind], "null") == 0) {
optind++;
data.writeStrongBinder(NULL);
} else if (strcmp(argv[optind], "intent") == 0) {
char* action = NULL;
char* dataArg = NULL;
char* type = NULL;
int launchFlags = 0;
char* component = NULL;
int categoryCount = 0;
char* categories[16];
char* context1 = NULL;
optind++;
while (optind < argc)
{
char* key = strtok_r(argv[optind], "=", &context1);
char* value = strtok_r(NULL, "=", &context1);
// we have reached the end of the XXX=XXX args.
if (key == NULL) break;
if (strcmp(key, "action") == 0)
{
action = value;
}
else if (strcmp(key, "data") == 0)
{
dataArg = value;
}
else if (strcmp(key, "type") == 0)
{
type = value;
}
else if (strcmp(key, "launchFlags") == 0)
{
launchFlags = atoi(value);
}
else if (strcmp(key, "component") == 0)
{
component = value;
}
else if (strcmp(key, "categories") == 0)
{
char* context2 = NULL;
int categoryCount = 0;
categories[categoryCount] = strtok_r(value, ",", &context2);
while (categories[categoryCount] != NULL)
{
categoryCount++;
categories[categoryCount] = strtok_r(NULL, ",", &context2);
}
}
optind++;
}
writeString16(data, action);
writeString16(data, dataArg);
writeString16(data, type);
data.writeInt32(launchFlags);
writeString16(data, component);
if (categoryCount > 0)
{
data.writeInt32(categoryCount);
for (int i = 0 ; i < categoryCount ; i++)
{
writeString16(data, categories[i]);
}
}
else
{
data.writeInt32(0);
}
// for now just set the extra field to be null.
data.writeInt32(-1);
} else {
aerr << "service: unknown option " << argv[optind] << endl;
wantsUsage = true;
result = 10;
break;
}
}
service->transact(code, data, &reply);//调用binder的transact函数,像相关service传递数据
aout << "Result: " << reply << endl;
} else {
aerr << "service: Service " << argv[serviceArg]
<< " does not exist" << endl;
result = 10;
}
} else {
if (optind < argc) {
aerr << "service: No service specified for call" << endl;
} else {
aerr << "service: No code specified for call" << endl;
}
wantsUsage = true;
result = 10;
}
} else {
aerr << "service: Unknown command " << argv[optind] << endl;
wantsUsage = true;
result = 10;
}
}
有了service call这个命令非常实用,比如我们自己写个service,也可以使用这个命令,来调试各个binder接口。