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 ...
随机推荐
- 版本控制-cvs
我们实训用的是cvs. 团队协作: 代码版本控制软件:CVS.SVN.GIT(Git@开源中国) FTP:服务端.客户端 CVS: 服务端(源码仓库).客户端
- SQL Server 2012 LocalDB 管理之旅
SQL Server LocalDB能够最大限度地节省您的数据库管理精力,以便开发人员可以专注于开发数据库应用. 使用SqlLocalDB命令行管理LocalDB 为了方便管理,LocalDB提供了一 ...
- ActionScript:Resampling PCM data
使用基于flash的麦克风录音,如果想在获取完PCM采样数据后,通过Sound马上回放,必须经过resampling.(注意:如果录音是采用的44KHz的话,则不需要) 因此,需要as实现一个简便的函 ...
- Switch Case语句中多个值匹配同一个代码块的写法
switch ($p) { case 'home': case '': $current_home = 'current'; break; case 'users.online': case 'use ...
- OC - 30.如何封装自定义布局
概述 对于经常使用的控件或类,通常将其分装为一个单独的类来供外界使用,以此达到事半功倍的效果 由于分装的类不依赖于其他的类,所以若要使用该类,可直接将该类拖进项目文件即可 在进行分装的时候,通常需要用 ...
- 安装SQLServer2008后Windows防火墙上的端口开放
1.打开SQL Server 配置管理器-->SQL Server 网络配置-->XXX的协议,启用TCP/IP协议2.打开TCP/IP协议的属性,切至“IP地址”标签,拉至最下端的IPA ...
- Vijos1523 NOI2002 贪吃的九头龙 树形dp
思路不算很难,但细节处理很麻烦 前面建图.多叉转二叉,以及确定dp处理序列的过程都是套路,dp的状态转移过程以注释的形式阐述 #include <cstdio> #include < ...
- SGU 163.Wise King
一道题目长的水题.... 总结就一句话,给出n个(-3~3)的数,一个数m,取任意个数是使这些数的m次幂之和最大. code #include <iostream> #include &l ...
- stat 的名字接口
File::stat - stat 的名字接口 名字为:dev, ino, mode, nlink, uid, gid, rdev, size, atime, mtime, ctime, blksiz ...
- python split()黑魔法
split()用法: #!/usr/bin/python str = "Line1-abcdef \nLine2-abc \nLine4-abcd"; print str.spli ...