最近碰到一个问题user版本不能使用adb问题。这个问题涉及到adbd和Usb相关的service代码。
一、adbd
我们先看看adbd对user版本的代码:
首先在adb_main函数中有如下代码,当ro.adb.secure属性为0的时候auth_required 变量为false。这个时候一般是debug版本(不会设置这个属性或者这个属性为0)
if (ALLOW_ADBD_NO_AUTH && property_get_bool("ro.adb.secure", 0) == 0) {
auth_required = false;
}
然后我们再来看adb.cpp中handle_packet函数,来处理pc侧发过来的数据包,当是debug版本时,直接会调用send_connect和pc侧连接,而当user版本时会调用send_auth_request验证。
case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
/* XXX verify version, etc */
if(t->connection_state != CS_OFFLINE) {
t->connection_state = CS_OFFLINE;
handle_offline(t);
LOG("%s: A_CNXN handle_offline\n", __FUNCTION__);
}
parse_banner(reinterpret_cast<const char*>(p->data), t);
if (HOST || !auth_required) {//HOST侧或者debug版本
handle_online(t);
LOG("%s: A_CNXN handle_online\n", __FUNCTION__);
if (!HOST) {
send_connect(t);
LOG("%s: A_CNXN send_connect\n", __FUNCTION__);
}
} else {
send_auth_request(t);
}
break;
我们来看下send_auth_request函数,发送了command是A_AUTH,arg0 = ADB_AUTH_TOKEN
void send_auth_request(atransport *t)
{
D("Calling send_auth_request\n");
apacket *p;
int ret;
ret = adb_auth_generate_token(t->token, sizeof(t->token));
if (ret != sizeof(t->token)) {
D("Error generating token ret=%d\n", ret);
return;
}
p = get_apacket();
memcpy(p->data, t->token, ret);
p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_TOKEN;
p->msg.data_length = ret;
send_packet(p, t);
}
再来看ADB_AUTH_TOKEN的处理,正常会调用send_auth_publickey函数
case A_AUTH:
if (p->msg.arg0 == ADB_AUTH_TOKEN) {
t->connection_state = CS_UNAUTHORIZED;
t->key = adb_auth_nextkey(t->key);
if (t->key) {
send_auth_response(p->data, p->msg.data_length, t);
} else {
/* No more private keys to try, send the public key */
send_auth_publickey(t);
}
}
send_auth_publickey如下,会发送ADB_AUTH_RSAPUBLICKEY
void send_auth_publickey(atransport *t)
{
D("Calling send_auth_publickey\n");
apacket *p = get_apacket();
int ret;
ret = adb_auth_get_userkey(p->data, sizeof(p->data));
if (!ret) {
D("Failed to get user public key\n");
put_apacket(p);
return;
}
p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
p->msg.data_length = ret;
send_packet(p, t);
}
处理ADB_AUTH_RSAPUBLICKEY会调用adb_auth_confirm_key函数
} else if (p->msg.arg0 == ADB_AUTH_RSAPUBLICKEY) {
adb_auth_confirm_key(p->data, p->msg.data_length, t);
}
adb_auth_confirm_key会通过socket往上层发送key,然后会触发adb_auth_event事件
void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
{
char msg[MAX_PAYLOAD];
int ret;
if (!usb_transport) {
usb_transport = t;
add_transport_disconnect(t, &usb_disconnect);
}
if (framework_fd < 0) {
D("Client not connected\n");
needs_retry = true;
return;
}
if (key[len - 1] != '\0') {
D("Key must be a null-terminated string\n");
return;
}
ret = snprintf(msg, sizeof(msg), "PK%s", key);//key数据
if (ret >= (signed)sizeof(msg)) {
D("Key too long. ret=%d", ret);
return;
}
D("Sending '%s'\n", msg);
ret = unix_write(framework_fd, msg, ret);//往上层socket写数据
if (ret < 0) {
D("Failed to write PK, errno=%d\n", errno);
return;
}
fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t);//注册事件
fdevent_add(&t->auth_fde, FDE_READ);
}
我们先来看下adb_auth_event的注册事件,如果有数据最终会调用adb_auth_verified函数
static void adb_auth_event(int fd, unsigned events, void *data)
{
char response[2];
int ret;
if (events & FDE_READ) {
ret = unix_read(fd, response, sizeof(response));
if (ret <= 0) {
D("Framework disconnect\n");
if (usb_transport)
fdevent_remove(&usb_transport->auth_fde);
framework_fd = -1;
}
else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
if (usb_transport)
adb_auth_verified(usb_transport);
}
}
}
而在adb_auth_verified函数中会和pc侧连接。
void adb_auth_verified(atransport *t)
{
handle_online(t);
send_connect(t);
}
二、Usb相关service
我们再来看下framework层
在UsbDeviceManager的构造函数有如下代码,当ro.adb.secure为true时(user版本)会创建UsbDebuggingManager对象
boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false);
boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));
if (secureAdbEnabled && !dataEncrypted) {
mDebuggingManager = new UsbDebuggingManager(context);
}
而当调用UsbDeviceManager的setAdbEnabled函数,最终会调用mDebuggingManager.setAdbEnabled函数
private void setAdbEnabled(boolean enable) {
if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
if (enable != mAdbEnabled) {
mAdbEnabled = enable;
// Due to the persist.sys.usb.config property trigger, changing adb state requires
// persisting default function
if(!mCurrentFunctions.equals(UsbManager.USB_FUNCTION_CHARGING)){
String oldFunctions = getDefaultFunctions();
String newFunctions = applyAdbFunction(oldFunctions);
if (!oldFunctions.equals(newFunctions)) {
setUsbPersistConfig(newFunctions);
}
// After persisting them use the lock-down aware function set
setEnabledFunctions(mCurrentFunctions, false);
updateAdbNotification();
}
}
if (mDebuggingManager != null) {
mDebuggingManager.setAdbEnabled(mAdbEnabled);
}
}
UsbDeviceManager会检测Settings的数据库Settings.Global.ADB_ENABLED值,发生变化会调用MSG_ENABLE_ADB消息,在这个消息中就会调用setAdbEnabled函数
private class AdbSettingsObserver extends ContentObserver {
public AdbSettingsObserver() {
super(null);
}
@Override
public void onChange(boolean selfChange) {
boolean enable = (Settings.Global.getInt(mContentResolver,
Settings.Global.ADB_ENABLED, 0) > 0);
mHandler.sendMessage(MSG_ENABLE_ADB, enable);
}
}
我们再来看UsbDebuggingManager的setAdbEnabled函数,会发送一个MESSAGE_ADB_ENABLED消息
public void setAdbEnabled(boolean enabled) {
mHandler.sendEmptyMessage(enabled ? UsbDebuggingHandler.MESSAGE_ADB_ENABLED
: UsbDebuggingHandler.MESSAGE_ADB_DISABLED);
}
这个消息的处理,会启动UsbDebuggingThread线程
case MESSAGE_ADB_ENABLED:
if (mAdbEnabled)
break;
mAdbEnabled = true;
mThread = new UsbDebuggingThread();
mThread.start();
break;
UsbDebuggingThread线程的run函数如下,先会调用openSocketLocked函数和adbd的socket进行连接,然后调用listenToSocket函数读取adbd socket的数据
public void run() {
if (DEBUG) Slog.d(TAG, "Entering thread");
while (true) {
synchronized (this) {
if (mStopped) {
if (DEBUG) Slog.d(TAG, "Exiting thread");
return;
}
try {
openSocketLocked();
} catch (Exception e) {
/* Don't loop too fast if adbd dies, before init restarts it */
SystemClock.sleep(1000);
}
}
try {
listenToSocket();
} catch (Exception e) {
/* Don't loop too fast if adbd dies, before init restarts it */
SystemClock.sleep(1000);
}
}
}
openSocketLocked函数就是建立一个socket和adbd的socket连接
private void openSocketLocked() throws IOException {
try {
LocalSocketAddress address = new LocalSocketAddress(ADBD_SOCKET,
LocalSocketAddress.Namespace.RESERVED);
mInputStream = null;
if (DEBUG) Slog.d(TAG, "Creating socket");
mSocket = new LocalSocket();
mSocket.connect(address);
mOutputStream = mSocket.getOutputStream();
mInputStream = mSocket.getInputStream();
} catch (IOException ioe) {
closeSocketLocked();
throw ioe;
}
}
listenToSocket函数,就是获取adbd 发过来的key值,然后发送MESSAGE_ADB_CONFIRM消息
private void listenToSocket() throws IOException {
try {
byte[] buffer = new byte[BUFFER_SIZE];
while (true) {
int count = mInputStream.read(buffer);
if (count < 0) {
break;
}
if (buffer[0] == 'P' && buffer[1] == 'K') {
String key = new String(Arrays.copyOfRange(buffer, 2, count));
Slog.d(TAG, "Received public key: " + key);
Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_CONFIRM);
msg.obj = key;
mHandler.sendMessage(msg);
} else {
Slog.e(TAG, "Wrong message: "
+ (new String(Arrays.copyOfRange(buffer, 0, 2))));
break;
}
}
} finally {
synchronized (this) {
closeSocketLocked();
}
}
}
这个消息处理,如果没有问题会调用startConfirmation函数,这个函数最后会启动UsbDebuggingActivity,这个Activity就是是否允许这台pc和手机连接等。
private void startConfirmation(String key, String fingerprints) {
int currentUserId = ActivityManager.getCurrentUser();
UserHandle userHandle =
UserManager.get(mContext).getUserInfo(currentUserId).getUserHandle();
String componentString;
if (currentUserId == UserHandle.USER_OWNER) {
componentString = Resources.getSystem().getString(
com.android.internal.R.string.config_customAdbPublicKeyConfirmationComponent);
} else {
// If the current foreground user is not the primary user we send a different
// notification specific to secondary users.
componentString = Resources.getSystem().getString(
R.string.config_customAdbPublicKeyConfirmationSecondaryUserComponent);
}
ComponentName componentName = ComponentName.unflattenFromString(componentString);
if (startConfirmationActivity(componentName, userHandle, key, fingerprints)
|| startConfirmationService(componentName, userHandle, key, fingerprints)) {
return;
}
Slog.e(TAG, "unable to start customAdbPublicKeyConfirmation[SecondaryUser]Component "
+ componentString + " as an Activity or a Service");
}
而在UsbDebuggingActivity最终调用点击允许,会调用UsbService的allowUsbDebugging函数,然后调用UsbDevicemanager的allowUsbDebugging函数,再到UsbDebuggingManager的allowUsbDebugging函数
@Override
public void onClick(DialogInterface dialog, int which) {
boolean allow = (which == AlertDialog.BUTTON_POSITIVE);
boolean alwaysAllow = allow && mAlwaysAllow.isChecked();
try {
IBinder b = ServiceManager.getService(USB_SERVICE);
IUsbManager service = IUsbManager.Stub.asInterface(b);
if (allow) {
service.allowUsbDebugging(alwaysAllow, mKey);
} else {
service.denyUsbDebugging();
}
} catch (Exception e) {
Log.e(TAG, "Unable to notify Usb service", e);
}
finish();
}
我们来看下UsbDebuggingManager的allowUsbDebugging函数,就是发送一个MESSAGE_ADB_ALLOW消息
public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_ALLOW);
msg.arg1 = alwaysAllow ? 1 : 0;
msg.obj = publicKey;
mHandler.sendMessage(msg);
}
我们来看下MESSAGE_ADB_ALLOW消息的处理,先调用writeKey,把key保存在文件中,然后调用thread的sendRespose给adbd发送ok消息。
case MESSAGE_ADB_ALLOW: {
String key = (String)msg.obj;
String fingerprints = getFingerprints(key);
if (!fingerprints.equals(mFingerprints)) {
Slog.e(TAG, "Fingerprints do not match. Got "
+ fingerprints + ", expected " + mFingerprints);
break;
}
if (msg.arg1 == 1) {
writeKey(key);
}
if (mThread != null) {
mThread.sendResponse("OK");
}
break;
}
我们先来看writeKey函数,先调用getUserKeyFile来获取文件,然后写入。
private void writeKey(String key) {
try {
File keyFile = getUserKeyFile();
if (keyFile == null) {
return;
}
if (!keyFile.exists()) {
keyFile.createNewFile();
FileUtils.setPermissions(keyFile.toString(),
FileUtils.S_IRUSR | FileUtils.S_IWUSR |
FileUtils.S_IRGRP, -1, -1);
}
FileOutputStream fo = new FileOutputStream(keyFile, true);
fo.write(key.getBytes());
fo.write('\n');
fo.close();
}
catch (IOException ex) {
Slog.e(TAG, "Error writing key:" + ex);
}
}
getUserKeyFile函数最终生成data/misc/adb/adb_keys文件
private File getUserKeyFile() {
File dataDir = Environment.getDataDirectory();
File adbDir = new File(dataDir, ADB_DIRECTORY);
if (!adbDir.exists()) {
Slog.e(TAG, "ADB data directory does not exist");
return null;
}
return new File(adbDir, ADB_KEYS_FILE);
}
然后我们再来看UsbDebuggingThread的sendResponse函数,就是给adbd发送一个ok消息。
void sendResponse(String msg) {
synchronized (this) {
if (!mStopped && mOutputStream != null) {
try {
mOutputStream.write(msg.getBytes());
}
catch (IOException ex) {
Slog.e(TAG, "Failed to write response:", ex);
}
}
}
}
三、adbd的socket
我们先来看初始化,初始化当adbd socket有数据来(就是连接),调用adb_auth_listener函数
void adbd_auth_init(void) {
int fd = android_get_control_socket("adbd");
if (fd == -1) {
D("Failed to get adbd socket\n");
return;
}
if (listen(fd, 4) == -1) {
D("Failed to listen on '%d'\n", fd);
return;
}
fdevent_install(&listener_fde, fd, adb_auth_listener, NULL);
fdevent_add(&listener_fde, FDE_READ);
}
adb_auth_listener函数就是accept usb service过来的socket,然后把其fd保存在framework_fd中。
static void adb_auth_listener(int fd, unsigned events, void *data)
{
struct sockaddr addr;
socklen_t alen;
int s;
alen = sizeof(addr);
s = adb_socket_accept(fd, &addr, &alen);
if (s < 0) {
D("Failed to accept: errno=%d\n", errno);
return;
}
framework_fd = s;
if (needs_retry) {
needs_retry = false;
send_auth_request(usb_transport);
}
}
当有key要发送给UsbDebuggingManager时,就调用adb_auth_confirm_key函数
void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
{
char msg[MAX_PAYLOAD];
int ret;
if (!usb_transport) {
usb_transport = t;
add_transport_disconnect(t, &usb_disconnect);
}
if (framework_fd < 0) {
D("Client not connected\n");
needs_retry = true;
return;
}
if (key[len - 1] != '\0') {
D("Key must be a null-terminated string\n");
return;
}
ret = snprintf(msg, sizeof(msg), "PK%s", key);
if (ret >= (signed)sizeof(msg)) {
D("Key too long. ret=%d", ret);
return;
}
D("Sending '%s'\n", msg);
ret = unix_write(framework_fd, msg, ret);//发送到UsbDebuggingManager
if (ret < 0) {
D("Failed to write PK, errno=%d\n", errno);
return;
}
fdevent_install(&t->auth_fde, framework_fd, adb_auth_event, t);//注册UsbDebuggingManager的socket fd事件
fdevent_add(&t->auth_fde, FDE_READ);
}
而且当UsbDebuggingManager的socket发来数据,我们会调用adb_auth_event函数。
这个函数最终读到UsbDebuggingManager的socket发来的消息是“OK”,就会调用adb_auth_verified函数,而这个函数最终会连接pc侧。
static void adb_auth_event(int fd, unsigned events, void *data)
{
char response[2];
int ret;
if (events & FDE_READ) {
ret = unix_read(fd, response, sizeof(response));
if (ret <= 0) {
D("Framework disconnect\n");
if (usb_transport)
fdevent_remove(&usb_transport->auth_fde);
framework_fd = -1;
}
else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
if (usb_transport)
adb_auth_verified(usb_transport);
}
}
}
四、问题解决
这样原理我们很清楚裂,问题也就迎刃而解了,我在手机收直接dumpsys usb,发现没有UsbDebuggingManager的dump数据,那只有一种可能,没有UsbDebuggingManager对象,也就是ro.adb.secure为false,按理说user版本这个属性为true。
这样我们就只用看相关编译的mk文件,有没有在user版本的时候,定义这个属性为1.发现没有,就修改device.mk如下,
ifeq ($(TARGET_BUILD_VARIANT),user)
PRODUCT_DEFAULT_PROPERTY_OVERRIDES+= \
ro.adb.secure=1
endif
这样问题就搞定了。