Android USB安全调试
Android 4.2.2 引入了USB安全调试方面的内容,当启用安全调试的时候,只有被用户认证过的主机才可以通过Android SDK自带的ADB工具经由USB连接来访问设备的内部构件。
下面以android-4.3_r3.1源码分析其实现:
首先打 usb调试界面在systemui中的UsbDebuggingActivity.java实现:

public class UsbDebuggingActivity extends AlertActivity
implements DialogInterface.OnClickListener {
private static final String TAG = "UsbDebuggingActivity"; private CheckBox mAlwaysAllow;
private UsbDisconnectedReceiver mDisconnectedReceiver;
private String mKey; @Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle); if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
} Intent intent = getIntent();
String fingerprints = intent.getStringExtra("fingerprints");
mKey = intent.getStringExtra("key"); if (fingerprints == null || mKey == null) {
finish();
return;
} final AlertController.AlertParams ap = mAlertParams;
ap.mTitle = getString(R.string.usb_debugging_title);
ap.mIconId = com.android.internal.R.drawable.ic_dialog_usb;
ap.mMessage = getString(R.string.usb_debugging_message, fingerprints);
ap.mPositiveButtonText = getString(android.R.string.ok);
ap.mNegativeButtonText = getString(android.R.string.cancel);
ap.mPositiveButtonListener = this;
ap.mNegativeButtonListener = this; // add "always allow" checkbox
LayoutInflater inflater = LayoutInflater.from(ap.mContext);
View checkbox = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
mAlwaysAllow = (CheckBox)checkbox.findViewById(com.android.internal.R.id.alwaysUse);
mAlwaysAllow.setText(getString(R.string.usb_debugging_always));
ap.mView = checkbox; setupAlert();
} private class UsbDisconnectedReceiver extends BroadcastReceiver {
private final Activity mActivity;
public UsbDisconnectedReceiver(Activity activity) {
mActivity = activity;
} @Override
public void onReceive(Context content, Intent intent) {
String action = intent.getAction();
if (!UsbManager.ACTION_USB_STATE.equals(action)) {
return;
}
boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
if (!connected) {
mActivity.finish();
}
}
} @Override
public void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
registerReceiver(mDisconnectedReceiver, filter);
} @Override
protected void onStop() {
if (mDisconnectedReceiver != null) {
unregisterReceiver(mDisconnectedReceiver);
}
super.onStop();
} @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.java中:

public class UsbDebuggingManager implements Runnable {
private static final String TAG = "UsbDebuggingManager";
private static final boolean DEBUG = false;
private final String ADBD_SOCKET = "adbd";
private final String ADB_DIRECTORY = "misc/adb";
private final String ADB_KEYS_FILE = "adb_keys";
private final int BUFFER_SIZE = 4096;
...
class UsbDebuggingHandler extends Handler {
private static final int MESSAGE_ADB_ENABLED = 1;
private static final int MESSAGE_ADB_DISABLED = 2;
private static final int MESSAGE_ADB_ALLOW = 3;
private static final int MESSAGE_ADB_DENY = 4;
private static final int MESSAGE_ADB_CONFIRM = 5;
private static final int MESSAGE_ADB_CLEAR = 6;
public UsbDebuggingHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_ADB_ENABLED:
if (mAdbEnabled)
break;
mAdbEnabled = true;
mThread = new Thread(UsbDebuggingManager.this);
mThread.start();
break;
case MESSAGE_ADB_DISABLED:
if (!mAdbEnabled)
break;
mAdbEnabled = false;
closeSocket();
try {
mThread.join();
} catch (Exception ex) {
}
mThread = null;
mOutputStream = null;
mSocket = null;
break;
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);
}
sendResponse("OK");
break;
}
case MESSAGE_ADB_DENY:
sendResponse("NO");
break;
case MESSAGE_ADB_CONFIRM: {
String key = (String)msg.obj;
mFingerprints = getFingerprints(key);
showConfirmationDialog(key, mFingerprints);
break;
}
case MESSAGE_ADB_CLEAR:
deleteKeyFile();
break;
}
}
}
private String getFingerprints(String key) {
String hex = "0123456789ABCDEF";
StringBuilder sb = new StringBuilder();
MessageDigest digester;
try {
digester = MessageDigest.getInstance("MD5");
} catch (Exception ex) {
Slog.e(TAG, "Error getting digester: " + ex);
return "";
}
byte[] base64_data = key.split("\\s+")[0].getBytes();
byte[] digest = digester.digest(Base64.decode(base64_data, Base64.DEFAULT));
for (int i = 0; i < digest.length; i++) {
sb.append(hex.charAt((digest[i] >> 4) & 0xf));
sb.append(hex.charAt(digest[i] & 0xf));
if (i < digest.length - 1)
sb.append(":");
}
return sb.toString();
}
private void showConfirmationDialog(String key, String fingerprints) {
Intent dialogIntent = new Intent();
dialogIntent.setClassName("com.android.systemui",
"com.android.systemui.usb.UsbDebuggingActivity");
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
dialogIntent.putExtra("key", key);
dialogIntent.putExtra("fingerprints", fingerprints);
try {
mContext.startActivity(dialogIntent);
} catch (ActivityNotFoundException e) {
Slog.e(TAG, "unable to start UsbDebuggingActivity");
}
}
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);
}
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);
}
}
private void deleteKeyFile() {
File keyFile = getUserKeyFile();
if (keyFile != null) {
keyFile.delete();
}
}
可见,若要删除特定连接Android设备的电脑只能删除Android设备中的文件:/data/misc/adb/adb_keys,或将Android设备强制刷机。
Android USB安全调试的更多相关文章
- 在Mac系统上配置Android真机调试环境
在Mac系统上配置Android真机调试环境 mac上配置安卓环境还说挺方便的,真机调试也比win上要好一些.win上被各种软件强行安装了xxx助手. 在mac上就了一个干净的感觉. 下载Androi ...
- 在android设备上调试ionic应用
方法1: ionic run android -l -c 将会在console中输出日志信息 方法2: (1).使用usb连接android设备,并打开android设备的调试功能 (2).在chro ...
- chrome inspect 远程调测:Chrome on Android之一 普通调试
本文PC环境: Chrome: 版本 33.0.1750.22 dev MAC OS:OS X 10.9.1 特别注意:Chrome DevToolsl使用时会联接到appspot.com,而此网址被 ...
- I.MX6 Android USB Touch eGTouchA.ini文件存放
/******************************************************************** * I.MX6 Android USB Touch eGTo ...
- android usb Host模式下与usb Hid 设备的通信
做android 与USB HID设备的通信有段时间了,总结一下遇到的问题和解决方法: 1,第一次遇到的问题:android 版本低不支持usb hid, 被要求做相关项目的时候,就从mUsbMana ...
- 杭州蓝松科技推出的安卓端的USB转串口调试助手, 欢迎下载使用
杭州蓝松科技推出的安卓端的USB转串口调试助手, 欢迎下载使用 下载地址:http://files.cnblogs.com/guobaPlayer/%E8%93%9D%E6%9D%BEUSB%E4%B ...
- [Android] [putty连接Android设备] [Android设备网络调试]
file: system/core/adb/adb.c line: 921 /* for the device, start the usb transport if the ** android u ...
- Unity Profiler连接Android真机调试
Profiler在Editor模式就可以观看性能消耗,但是毕竟电脑配置高,跟手机真机环境还是有区别.实际开发中的优化还是推荐用真机测试. 因为IOS一般比Android手机的配置高,在Android平 ...
- Android内存泄露调试
Android 内存泄漏调试 一.概述 如果我们编写的代码当中有太多的对内存使用不当的地方,难免会使得我们的设备运行缓慢,甚至是死机.为了能够使得 Android 应用程序安全且快速的运行, Andr ...
随机推荐
- C# 内存管理优化畅想(三)---- 其他方法&结语
前两篇文章提出的优化方法,都是不需要修改源代码的,而是在CLR或JIT层面进行自动优化的.但本文中提出的优化方法则需要引入新的语法,开发者只有在源代码中使用了这些新语法,才会获得优化. 1. 允许对象 ...
- STM32串口通信USART1转USART2问题解决
使用的是STM32f103ZET6. 1.把文件main.c和usart.c中的所有usart1换成usart2 2.查看手册得知USART2的引脚是Tx->PA2,Rx->PA3,改变u ...
- How to customize authentication to my own set of tables in asp.net web api 2?
ssuming your table is called AppUser, convert your own AppUser domain object to IUser(using Microsof ...
- log4Net配置详解
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSe ...
- 对数据预处理的一点理解[ZZ]
数据预处理没有统一的标准,只能说是根据不同类型的分析数据和业务需求,在对数据特性做了充分的理解之后,再选择相关的数据预处理技术,一般会用到多种预处理技术,而且对每种处理之后的效果做些分析对比,这里面经 ...
- Xcode 使用自定义字体
添加对应的字体(.ttf或.odf)到工程的resurce,使用cocos2d中的FontLabel库,FontLabel继承于UILabel,象UILabel一样使用就好了 fontName直接使用 ...
- JqGrid自定义toolbar
1.设置toolbar参数为[true,"top"],其意思是toolbar显示在Grid顶部,且其id为t_+Grid的id.e.g.: Grid的id为myGrid,toolb ...
- ASP.Net数据导出Excel的几种方法
方法一 通过GridView(简评:方法比较简单,但是只适合生成格式简单的Excel,且无法保留VBA代码),页面无刷新 aspx.cs部分 代码如下: using System; using Sys ...
- PHP数据库
目录 1.创建数据库连接 2.创建数据库 3.选择数据库 4.设置当前连接使用的字符编码 5.创建表 6.插入数据 7.取得数据查询结果 8.关闭连接 1.创建数据库连接 //mysql_connec ...
- PHP中截取中文乱码
大家都知道,一个汉字在gb2312下面是占2个字节,用传统的substr肯定会出问题 ,所以应该用,mb_substr和mb_strcut两个函数 在这个之前,打开php.ini打开php_mbstr ...