http://blog.csdn.net/zimo2013/article/details/38950363
1.简介
最近做一个项目,主要通过usb完成pc与Android端的数据传输。但是根据api提供的无法监听usb的插拔,有解释为不同版本会存在BUG。本打算放弃跳过监听usb,改为在连上usb后pc点击按钮发出一个广播来主动打开Android端的应用程序,然后通过socket完成数据交互。这里主要通过UEventObserver,而该类位于/frameworks/base/core/java/android/os/UEventObserver.java中,位于framework框架。需要手动导入编译好的frameworks,下载frameworks.jar。
2.如何导入frameworks.jar
在工程的Build Path 中,Add External JARs中选择frameworks.jar,然后需要最好配置Order中将frameworks.jar置前,对于定制的frameworks也可以这样导入。
3.实现UEventObserver
public class MyService extends Service { private final static String TAG = SMSService.class.getSimpleName(); private UsbUEventObserver usbObserver = null; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); LogUtil.d(TAG, "onCreate()"); usbObserver = new UsbUEventObserver(); usbObserver.startObserving(USB_STATE_MATCH); usbObserver.startObserving(ACCESSORY_START_MATCH); } public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { // } return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { LogUtil.d(TAG, "onDestroy()"); if (usbObserver != null) { usbObserver.stopObserving(); } super.onDestroy(); } private static final String USB_STATE_MATCH = "DEVPATH=/devices/virtual/android_usb/android0"; private static final String ACCESSORY_START_MATCH = "DEVPATH=/devices/virtual/misc/usb_accessory"; private class UsbUEventObserver extends UEventObserver { @Override public void onUEvent(final UEventObserver.UEvent event) { LogUtil.i(TAG, "usb:" + event.toString()); final String state = event.get("USB_STATE"); final String accessory = event.get("ACCESSORY"); if (state != null) { // mHandler.updateState(state); if (state.equalsIgnoreCase("CONNECTED")) { Intent intent2 = new Intent(getApplicationContext(), MainActivity.class); intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getApplicationContext().startActivity(intent2); BroadUtil.sendBroadcastConnected(getApplicationContext(), Constants.ConnectedType.USB_CONNECTED); } else if (state.toUpperCase().contains("DISCONNECTED")) { BroadUtil.sendBroadcastConnected(getApplicationContext(), Constants.ConnectedType.USB_DISCONNECTED); } } else if ("START".equals(accessory)) { // startAccessoryMode(); } } }; }
4.附UsbDeviceManager源码
/** * UsbDeviceManager manages USB state in device mode. */ public class UsbDeviceManager { private static final String TAG = UsbDeviceManager.class.getSimpleName(); private static final boolean DEBUG = false; private static final String USB_STATE_MATCH = "DEVPATH=/devices/virtual/android_usb/android0"; private static final String ACCESSORY_START_MATCH = "DEVPATH=/devices/virtual/misc/usb_accessory"; private static final String FUNCTIONS_PATH = "/sys/class/android_usb/android0/functions"; private static final String STATE_PATH = "/sys/class/android_usb/android0/state"; private static final String MASS_STORAGE_FILE_PATH = "/sys/class/android_usb/android0/f_mass_storage/lun/file"; private static final String RNDIS_ETH_ADDR_PATH = "/sys/class/android_usb/android0/f_rndis/ethaddr"; private static final int MSG_UPDATE_STATE = 0; private static final int MSG_ENABLE_ADB = 1; private static final int MSG_SET_CURRENT_FUNCTION = 2; private static final int MSG_SYSTEM_READY = 3; private static final int MSG_BOOT_COMPLETED = 4; // Delay for debouncing USB disconnects. // We often get rapid connect/disconnect events when enabling USB functions, // which need debouncing. private static final int UPDATE_DELAY = 1000; private UsbHandler mHandler; private boolean mBootCompleted; private final Context mContext; private final ContentResolver mContentResolver; private final UsbSettingsManager mSettingsManager; private NotificationManager mNotificationManager; private final boolean mHasUsbAccessory; private boolean mUseUsbNotification; private boolean mAdbEnabled; private class AdbSettingsObserver extends ContentObserver { public AdbSettingsObserver() { super(null); } @Override public void onChange(boolean selfChange) { boolean enable = (Settings.Secure.getInt(mContentResolver, Settings.Secure.ADB_ENABLED, 0) > 0); mHandler.sendMessage(MSG_ENABLE_ADB, enable); } } /* * Listens for uevent messages from the kernel to monitor the USB state */ private final UEventObserver mUEventObserver = new UEventObserver() { @Override public void onUEvent(UEventObserver.UEvent event) { if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString()); String state = event.get("USB_STATE"); String accessory = event.get("ACCESSORY"); if (state != null) { mHandler.updateState(state); } else if ("START".equals(accessory)) { if (DEBUG) Slog.d(TAG, "got accessory start"); setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false); } } }; public UsbDeviceManager(Context context, UsbSettingsManager settingsManager) { mContext = context; mContentResolver = context.getContentResolver(); mSettingsManager = settingsManager; PackageManager pm = mContext.getPackageManager(); mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY); initRndisAddress(); // create a thread for our Handler HandlerThread thread = new HandlerThread("UsbDeviceManager", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); mHandler = new UsbHandler(thread.getLooper()); if (nativeIsStartRequested()) { if (DEBUG) Slog.d(TAG, "accessory attached at boot"); setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false); } } public void systemReady() { if (DEBUG) Slog.d(TAG, "systemReady"); mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); // We do not show the USB notification if the primary volume supports mass storage. // The legacy mass storage UI will be used instead. boolean massStorageSupported = false; StorageManager storageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE); StorageVolume[] volumes = storageManager.getVolumeList(); if (volumes.length > 0) { massStorageSupported = volumes[0].allowMassStorage(); } mUseUsbNotification = !massStorageSupported; // make sure the ADB_ENABLED setting value matches the current state Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED, mAdbEnabled ? 1 : 0); mHandler.sendEmptyMessage(MSG_SYSTEM_READY); } private static void initRndisAddress() { // configure RNDIS ethernet address based on our serial number using the same algorithm // we had been previously using in kernel board files final int ETH_ALEN = 6; int address[] = new int[ETH_ALEN]; // first byte is 0x02 to signify a locally administered address address[0] = 0x02; String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF"); int serialLength = serial.length(); // XOR the USB serial across the remaining 5 bytes for (int i = 0; i < serialLength; i++) { address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i); } String addrString = String.format("%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1], address[2], address[3], address[4], address[5]); try { FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString); } catch (IOException e) { Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH); } } private static String addFunction(String functions, String function) { if (!containsFunction(functions, function)) { if (functions.length() > 0) { functions += ","; } functions += function; } return functions; } private static String removeFunction(String functions, String function) { String[] split = functions.split(","); for (int i = 0; i < split.length; i++) { if (function.equals(split[i])) { split[i] = null; } } StringBuilder builder = new StringBuilder(); for (int i = 0; i < split.length; i++) { String s = split[i]; if (s != null) { if (builder.length() > 0) { builder.append(","); } builder.append(s); } } return builder.toString(); } private static boolean containsFunction(String functions, String function) { int index = functions.indexOf(function); if (index < 0) return false; if (index > 0 && functions.charAt(index - 1) != ',') return false; int charAfter = index + function.length(); if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false; return true; } private final class UsbHandler extends Handler { // current USB state private boolean mConnected; private boolean mConfigured; private String mCurrentFunctions; private String mDefaultFunctions; private UsbAccessory mCurrentAccessory; private int mUsbNotificationId; private boolean mAdbNotificationShown; private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { if (DEBUG) Slog.d(TAG, "boot completed"); mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED); } }; public UsbHandler(Looper looper) { super(looper); try { // persist.sys.usb.config should never be unset. But if it is, set it to "adb" // so we have a chance of debugging what happened. mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb"); // sanity check the sys.usb.config system property // this may be necessary if we crashed while switching USB configurations String config = SystemProperties.get("sys.usb.config", "none"); if (!config.equals(mDefaultFunctions)) { Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions); SystemProperties.set("sys.usb.config", mDefaultFunctions); } mCurrentFunctions = mDefaultFunctions; String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); updateState(state); mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB); // Upgrade step for previous versions that used persist.service.adb.enable String value = SystemProperties.get("persist.service.adb.enable", ""); if (value.length() > 0) { char enable = value.charAt(0); if (enable == '1') { setAdbEnabled(true); } else if (enable == '0') { setAdbEnabled(false); } SystemProperties.set("persist.service.adb.enable", ""); } // register observer to listen for settings changes mContentResolver.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED), false, new AdbSettingsObserver()); // Watch for USB configuration changes mUEventObserver.startObserving(USB_STATE_MATCH); mUEventObserver.startObserving(ACCESSORY_START_MATCH); mContext.registerReceiver(mBootCompletedReceiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); } catch (Exception e) { Slog.e(TAG, "Error initializing UsbHandler", e); } } public void sendMessage(int what, boolean arg) { removeMessages(what); Message m = Message.obtain(this, what); m.arg1 = (arg ? 1 : 0); sendMessage(m); } public void sendMessage(int what, Object arg) { removeMessages(what); Message m = Message.obtain(this, what); m.obj = arg; sendMessage(m); } public void sendMessage(int what, Object arg0, boolean arg1) { removeMessages(what); Message m = Message.obtain(this, what); m.obj = arg0; m.arg1 = (arg1 ? 1 : 0); sendMessage(m); } public void updateState(String state) { int connected, configured; if ("DISCONNECTED".equals(state)) { connected = 0; configured = 0; } else if ("CONNECTED".equals(state)) { connected = 1; configured = 0; } else if ("CONFIGURED".equals(state)) { connected = 1; configured = 1; } else { Slog.e(TAG, "unknown state " + state); return; } removeMessages(MSG_UPDATE_STATE); Message msg = Message.obtain(this, MSG_UPDATE_STATE); msg.arg1 = connected; msg.arg2 = configured; // debounce disconnects to avoid problems bringing up USB tethering sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0); } private boolean waitForState(String state) { // wait for the transition to complete. // give up after 1 second. for (int i = 0; i < 20; i++) { // State transition is done when sys.usb.state is set to the new configuration if (state.equals(SystemProperties.get("sys.usb.state"))) return true; try { // try again in 50ms Thread.sleep(50); } catch (InterruptedException e) { } } Slog.e(TAG, "waitForState(" + state + ") FAILED"); return false; } private boolean setUsbConfig(String config) { if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")"); // set the new configuration SystemProperties.set("sys.usb.config", config); return waitForState(config); } 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 // switching to default function setEnabledFunctions(mDefaultFunctions, true); updateAdbNotification(); } } private void setEnabledFunctions(String functions, boolean makeDefault) { if (functions != null && makeDefault) { if (mAdbEnabled) { functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB); } else { functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB); } if (!mDefaultFunctions.equals(functions)) { if (!setUsbConfig("none")) { Slog.e(TAG, "Failed to disable USB"); // revert to previous configuration if we fail setUsbConfig(mCurrentFunctions); return; } // setting this property will also change the current USB state // via a property trigger SystemProperties.set("persist.sys.usb.config", functions); if (waitForState(functions)) { mCurrentFunctions = functions; mDefaultFunctions = functions; } else { Slog.e(TAG, "Failed to switch persistent USB config to " + functions); // revert to previous configuration if we fail SystemProperties.set("persist.sys.usb.config", mDefaultFunctions); } } } else { if (functions == null) { functions = mDefaultFunctions; } if (mAdbEnabled) { functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB); } else { functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB); } if (!mCurrentFunctions.equals(functions)) { if (!setUsbConfig("none")) { Slog.e(TAG, "Failed to disable USB"); // revert to previous configuration if we fail setUsbConfig(mCurrentFunctions); return; } if (setUsbConfig(functions)) { mCurrentFunctions = functions; } else { Slog.e(TAG, "Failed to switch USB config to " + functions); // revert to previous configuration if we fail setUsbConfig(mCurrentFunctions); } } } } private void updateCurrentAccessory() { if (!mHasUsbAccessory) return; if (mConfigured) { String[] strings = nativeGetAccessoryStrings(); if (strings != null) { mCurrentAccessory = new UsbAccessory(strings); Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); // defer accessoryAttached if system is not ready if (mBootCompleted) { mSettingsManager.accessoryAttached(mCurrentAccessory); } // else handle in mBootCompletedReceiver } else { Slog.e(TAG, "nativeGetAccessoryStrings failed"); } } else if (!mConnected) { // make sure accessory mode is off // and restore default functions Slog.d(TAG, "exited USB accessory mode"); setEnabledFunctions(mDefaultFunctions, false); if (mCurrentAccessory != null) { if (mBootCompleted) { mSettingsManager.accessoryDetached(mCurrentAccessory); } mCurrentAccessory = null; } } } private void updateUsbState() { // send a sticky broadcast containing current USB state Intent intent = new Intent(UsbManager.ACTION_USB_STATE); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(UsbManager.USB_CONNECTED, mConnected); intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured); if (mCurrentFunctions != null) { String[] functions = mCurrentFunctions.split(","); for (int i = 0; i < functions.length; i++) { intent.putExtra(functions[i], true); } } mContext.sendStickyBroadcast(intent); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_UPDATE_STATE: mConnected = (msg.arg1 == 1); mConfigured = (msg.arg2 == 1); updateUsbNotification(); updateAdbNotification(); if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) { updateCurrentAccessory(); } if (!mConnected) { // restore defaults when USB is disconnected setEnabledFunctions(mDefaultFunctions, false); } if (mBootCompleted) { updateUsbState(); } break; case MSG_ENABLE_ADB: setAdbEnabled(msg.arg1 == 1); break; case MSG_SET_CURRENT_FUNCTION: String function = (String)msg.obj; boolean makeDefault = (msg.arg1 == 1); setEnabledFunctions(function, makeDefault); break; case MSG_SYSTEM_READY: updateUsbNotification(); updateAdbNotification(); updateUsbState(); break; case MSG_BOOT_COMPLETED: mBootCompleted = true; if (mCurrentAccessory != null) { mSettingsManager.accessoryAttached(mCurrentAccessory); } break; } } public UsbAccessory getCurrentAccessory() { return mCurrentAccessory; } private void updateUsbNotification() { if (mNotificationManager == null || !mUseUsbNotification) return; int id = 0; Resources r = mContext.getResources(); if (mConnected) { if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) { id = com.android.internal.R.string.usb_mtp_notification_title; } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) { id = com.android.internal.R.string.usb_ptp_notification_title; } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MASS_STORAGE)) { id = com.android.internal.R.string.usb_cd_installer_notification_title; } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) { id = com.android.internal.R.string.usb_accessory_notification_title; } else { // There is a different notification for USB tethering so we don't need one here if (!containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) { Slog.e(TAG, "No known USB function in updateUsbNotification"); } } } if (id != mUsbNotificationId) { // clear notification if title needs changing if (mUsbNotificationId != 0) { mNotificationManager.cancel(mUsbNotificationId); mUsbNotificationId = 0; } if (id != 0) { CharSequence message = r.getText( com.android.internal.R.string.usb_notification_message); CharSequence title = r.getText(id); Notification notification = new Notification(); notification.icon = com.android.internal.R.drawable.stat_sys_data_usb; notification.when = 0; notification.flags = Notification.FLAG_ONGOING_EVENT; notification.tickerText = title; notification.defaults = 0; // please be quiet notification.sound = null; notification.vibrate = null; Intent intent = Intent.makeRestartActivityTask( new ComponentName("com.android.settings", "com.android.settings.UsbSettings")); PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); notification.setLatestEventInfo(mContext, title, message, pi); mNotificationManager.notify(id, notification); mUsbNotificationId = id; } } } private void updateAdbNotification() { if (mNotificationManager == null) return; final int id = com.android.internal.R.string.adb_active_notification_title; if (mAdbEnabled && mConnected) { if ("0".equals(SystemProperties.get("persist.adb.notify"))) return; if (!mAdbNotificationShown) { Resources r = mContext.getResources(); CharSequence title = r.getText(id); CharSequence message = r.getText( com.android.internal.R.string.adb_active_notification_message); Notification notification = new Notification(); notification.icon = com.android.internal.R.drawable.stat_sys_adb; notification.when = 0; notification.flags = Notification.FLAG_ONGOING_EVENT; notification.tickerText = title; notification.defaults = 0; // please be quiet notification.sound = null; notification.vibrate = null; Intent intent = Intent.makeRestartActivityTask( new ComponentName("com.android.settings", "com.android.settings.DevelopmentSettings")); PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); notification.setLatestEventInfo(mContext, title, message, pi); mAdbNotificationShown = true; mNotificationManager.notify(id, notification); } } else if (mAdbNotificationShown) { mAdbNotificationShown = false; mNotificationManager.cancel(id); } } public void dump(FileDescriptor fd, PrintWriter pw) { pw.println(" USB Device State:"); pw.println(" Current Functions: " + mCurrentFunctions); pw.println(" Default Functions: " + mDefaultFunctions); pw.println(" mConnected: " + mConnected); pw.println(" mConfigured: " + mConfigured); pw.println(" mCurrentAccessory: " + mCurrentAccessory); try { pw.println(" Kernel state: " + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim()); pw.println(" Kernel function list: " + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim()); pw.println(" Mass storage backing file: " + FileUtils.readTextFile(new File(MASS_STORAGE_FILE_PATH), 0, null).trim()); } catch (IOException e) { pw.println("IOException: " + e); } } } /* returns the currently attached USB accessory */ public UsbAccessory getCurrentAccessory() { return mHandler.getCurrentAccessory(); } /* opens the currently attached USB accessory */ public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { UsbAccessory currentAccessory = mHandler.getCurrentAccessory(); if (currentAccessory == null) { throw new IllegalArgumentException("no accessory attached"); } if (!currentAccessory.equals(accessory)) { String error = accessory.toString() + " does not match current accessory " + currentAccessory; throw new IllegalArgumentException(error); } mSettingsManager.checkPermission(accessory); return nativeOpenAccessory(); } public void setCurrentFunction(String function, boolean makeDefault) { if (DEBUG) Slog.d(TAG, "setCurrentFunction(" + function + ") default: " + makeDefault); mHandler.sendMessage(MSG_SET_CURRENT_FUNCTION, function, makeDefault); } public void setMassStorageBackingFile(String path) { if (path == null) path = ""; try { FileUtils.stringToFile(MASS_STORAGE_FILE_PATH, path); } catch (IOException e) { Slog.e(TAG, "failed to write to " + MASS_STORAGE_FILE_PATH); } } public void dump(FileDescriptor fd, PrintWriter pw) { if (mHandler != null) { mHandler.dump(fd, pw); } } private native String[] nativeGetAccessoryStrings(); private native ParcelFileDescriptor nativeOpenAccessory(); private native boolean nativeIsStartRequested(); }
时间: 2024-10-12 09:21:02