Loading services/core/jni/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \ $(LOCAL_REL_DIR)/com_android_server_vr_VrManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \ $(LOCAL_REL_DIR)/com_android_server_UsbDescriptorParser.cpp \ $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \ $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \ $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \ Loading services/core/jni/com_android_server_UsbDescriptorParser.cpp 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "UsbHostManagerJNI" #include "utils/Log.h" #include "jni.h" #include "JNIHelp.h" #include <usbhost/usbhost.h> #define MAX_DESCRIPTORS_LENGTH 16384 // com.android.server.usb.descriptors extern "C" { jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors( JNIEnv* env, jobject thiz, jstring deviceAddr) { const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL); struct usb_device* device = usb_device_open(deviceAddrStr); env->ReleaseStringUTFChars(deviceAddr, deviceAddrStr); if (!device) { ALOGE("usb_device_open failed"); return NULL; } int fd = usb_device_get_fd(device); if (fd < 0) { return NULL; } // from android_hardware_UsbDeviceConnection_get_desc() jbyte buffer[MAX_DESCRIPTORS_LENGTH]; lseek(fd, 0, SEEK_SET); int numBytes = read(fd, buffer, sizeof(buffer)); usb_device_close(device); jbyteArray ret = NULL; if (numBytes != 0) { ret = env->NewByteArray(numBytes); env->SetByteArrayRegion(ret, 0, numBytes, buffer); } return ret; } } // extern "C" services/usb/java/com/android/server/usb/UsbAlsaManager.java +27 −10 Original line number Diff line number Diff line Loading @@ -65,6 +65,9 @@ public final class UsbAlsaManager { private final HashMap<UsbDevice,UsbAudioDevice> mAudioDevices = new HashMap<UsbDevice,UsbAudioDevice>(); private boolean mIsInputHeadset; // as reported by UsbDescriptorParser private boolean mIsOutputHeadset; // as reported by UsbDescriptorParser private final HashMap<UsbDevice,UsbMidiDevice> mMidiDevices = new HashMap<UsbDevice,UsbMidiDevice>(); Loading Loading @@ -184,9 +187,14 @@ public final class UsbAlsaManager { try { // Playback Device if (audioDevice.mHasPlayback) { int device = (audioDevice == mAccessoryAudioDevice ? AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE); int device; if (mIsOutputHeadset) { device = AudioSystem.DEVICE_OUT_USB_HEADSET; } else { device = (audioDevice == mAccessoryAudioDevice ? AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE); } if (DEBUG) { Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) + " addr:" + address + " name:" + audioDevice.getDeviceName()); Loading @@ -197,9 +205,14 @@ public final class UsbAlsaManager { // Capture Device if (audioDevice.mHasCapture) { int device = (audioDevice == mAccessoryAudioDevice ? AudioSystem.DEVICE_IN_USB_ACCESSORY : AudioSystem.DEVICE_IN_USB_DEVICE); int device; if (mIsInputHeadset) { device = AudioSystem.DEVICE_IN_USB_HEADSET; } else { device = (audioDevice == mAccessoryAudioDevice ? AudioSystem.DEVICE_IN_USB_ACCESSORY : AudioSystem.DEVICE_IN_USB_DEVICE); } mAudioService.setWiredDeviceConnectionState( device, state, address, audioDevice.getDeviceName(), TAG); } Loading Loading @@ -343,12 +356,16 @@ public final class UsbAlsaManager { return selectAudioCard(mCardsParser.getDefaultCard()); } /* package */ void usbDeviceAdded(UsbDevice usbDevice) { /* package */ void usbDeviceAdded(UsbDevice usbDevice, boolean isInputHeadset, boolean isOutputHeadset) { if (DEBUG) { Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() + " nm:" + usbDevice.getProductName()); Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() + " nm:" + usbDevice.getProductName()); } mIsInputHeadset = isInputHeadset; mIsOutputHeadset = isOutputHeadset; // Is there an audio interface in there? boolean isAudioDevice = false; Loading services/usb/java/com/android/server/usb/UsbHostManager.java +9 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.server.usb; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; Loading @@ -32,6 +31,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.usb.descriptors.UsbDescriptorParser; import java.util.ArrayList; import java.util.HashMap; Loading Loading @@ -259,7 +259,14 @@ public class UsbHostManager { getCurrentUserSettings().deviceAttachedForFixedHandler(mNewDevice, usbDeviceConnectionHandler); } mUsbAlsaManager.usbDeviceAdded(mNewDevice); // deviceName is something like: "/dev/bus/usb/001/001" UsbDescriptorParser parser = new UsbDescriptorParser(); if (parser.parseDevice(mNewDevice.getDeviceName())) { Slog.i(TAG, "---- isHeadset[in:" + parser.isInputHeadset() + " , out:" + parser.isOutputHeadset() + "]"); mUsbAlsaManager.usbDeviceAdded(mNewDevice, parser.isInputHeadset(), parser.isOutputHeadset()); } } else { Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded"); } Loading services/usb/java/com/android/server/usb/descriptors/ByteStream.java 0 → 100644 +189 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.usb.descriptors; import android.annotation.NonNull; /** * @hide * A stream interface wrapping a byte array. Very much like a java.io.ByteArrayInputStream * but with the capability to "back up" in situations where the parser discovers that a * UsbDescriptor has overrun its length. */ public class ByteStream { private static final String TAG = "ByteStream"; /** The byte array being wrapped */ @NonNull private final byte[] mBytes; // this is never null. /** * The index into the byte array to be read next. * This value is altered by reading data out of the stream * (using either the getByte() or unpack*() methods), or alternatively * by explicitly offseting the stream position with either * advance() or reverse(). */ private int mIndex; /* * This member used with resetReadCount() & getReadCount() can be used to determine how many * bytes a UsbDescriptor subclass ACTUALLY reads (as opposed to what its length field says). * using this info, the parser can mark a descriptor as valid or invalid and correct the stream * position with advance() & reverse() to keep from "getting lost" in the descriptor stream. */ private int mReadCount; /** * Create a ByteStream object wrapping the specified byte array. * * @param bytes The byte array containing the raw descriptor information retrieved from * the USB device. * @throws IllegalArgumentException */ public ByteStream(@NonNull byte[] bytes) { if (bytes == null) { throw new IllegalArgumentException(); } mBytes = bytes; } /** * Resets the running count of bytes read so that later we can see how much more has been read. */ public void resetReadCount() { mReadCount = 0; } /** * Retrieves the running count of bytes read from the stream. */ public int getReadCount() { return mReadCount; } /** * @return The value of the next byte in the stream without advancing the stream. * Does not affect the running count as the byte hasn't been "consumed". * @throws IndexOutOfBoundsException */ public byte peekByte() { if (available() > 0) { return mBytes[mIndex + 1]; } else { throw new IndexOutOfBoundsException(); } } /** * @return the next byte from the stream and advances the stream and the read count. Note * that this is a signed byte (as is the case of byte in Java). The user may need to understand * from context if it should be interpreted as an unsigned value. * @throws IndexOutOfBoundsException */ public byte getByte() { if (available() > 0) { mReadCount++; return mBytes[mIndex++]; } else { throw new IndexOutOfBoundsException(); } } /** * Reads 2 bytes in *little endian format* from the stream and composes a 16-bit integer. * As we are storing the 2-byte value in a 4-byte integer, the upper 2 bytes are always * 0, essentially making the returned value *unsigned*. * @return The 16-bit integer (packed into the lower 2 bytes of an int) encoded by the * next 2 bytes in the stream. * @throws IndexOutOfBoundsException */ public int unpackUsbWord() { if (available() >= 2) { int b0 = getByte(); int b1 = getByte(); return ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF); } else { throw new IndexOutOfBoundsException(); } } /** * Reads 3 bytes in *little endian format* from the stream and composes a 24-bit integer. * As we are storing the 3-byte value in a 4-byte integer, the upper byte is always * 0, essentially making the returned value *unsigned*. * @return The 24-bit integer (packed into the lower 3 bytes of an int) encoded by the * next 3 bytes in the stream. * @throws IndexOutOfBoundsException */ public int unpackUsbTriple() { if (available() >= 3) { int b0 = getByte(); int b1 = getByte(); int b2 = getByte(); return ((b2 << 16) & 0x00FF0000) | ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF); } else { throw new IndexOutOfBoundsException(); } } /** * Advances the logical position in the stream. Affects the running count also. * @param numBytes The number of bytes to advance. * @throws IndexOutOfBoundsException * @throws IllegalArgumentException */ public void advance(int numBytes) { if (numBytes < 0) { // Positive offsets only throw new IllegalArgumentException(); } // do arithmetic and comparison in long to ovoid potention integer overflow long longNewIndex = (long) mIndex + (long) numBytes; if (longNewIndex < (long) mBytes.length) { mReadCount += numBytes; mIndex += numBytes; } else { throw new IndexOutOfBoundsException(); } } /** * Reverse the logical position in the stream. Affects the running count also. * @param numBytes The (positive) number of bytes to reverse. * @throws IndexOutOfBoundsException * @throws IllegalArgumentException */ public void reverse(int numBytes) { if (numBytes < 0) { // Positive (reverse) offsets only throw new IllegalArgumentException(); } if (mIndex >= numBytes) { mReadCount -= numBytes; mIndex -= numBytes; } else { throw new IndexOutOfBoundsException(); } } /** * @return The number of bytes available to be read in the stream. */ public int available() { return mBytes.length - mIndex; } } Loading
services/core/jni/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \ $(LOCAL_REL_DIR)/com_android_server_vr_VrManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \ $(LOCAL_REL_DIR)/com_android_server_UsbDescriptorParser.cpp \ $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \ $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \ $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \ Loading
services/core/jni/com_android_server_UsbDescriptorParser.cpp 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "UsbHostManagerJNI" #include "utils/Log.h" #include "jni.h" #include "JNIHelp.h" #include <usbhost/usbhost.h> #define MAX_DESCRIPTORS_LENGTH 16384 // com.android.server.usb.descriptors extern "C" { jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors( JNIEnv* env, jobject thiz, jstring deviceAddr) { const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL); struct usb_device* device = usb_device_open(deviceAddrStr); env->ReleaseStringUTFChars(deviceAddr, deviceAddrStr); if (!device) { ALOGE("usb_device_open failed"); return NULL; } int fd = usb_device_get_fd(device); if (fd < 0) { return NULL; } // from android_hardware_UsbDeviceConnection_get_desc() jbyte buffer[MAX_DESCRIPTORS_LENGTH]; lseek(fd, 0, SEEK_SET); int numBytes = read(fd, buffer, sizeof(buffer)); usb_device_close(device); jbyteArray ret = NULL; if (numBytes != 0) { ret = env->NewByteArray(numBytes); env->SetByteArrayRegion(ret, 0, numBytes, buffer); } return ret; } } // extern "C"
services/usb/java/com/android/server/usb/UsbAlsaManager.java +27 −10 Original line number Diff line number Diff line Loading @@ -65,6 +65,9 @@ public final class UsbAlsaManager { private final HashMap<UsbDevice,UsbAudioDevice> mAudioDevices = new HashMap<UsbDevice,UsbAudioDevice>(); private boolean mIsInputHeadset; // as reported by UsbDescriptorParser private boolean mIsOutputHeadset; // as reported by UsbDescriptorParser private final HashMap<UsbDevice,UsbMidiDevice> mMidiDevices = new HashMap<UsbDevice,UsbMidiDevice>(); Loading Loading @@ -184,9 +187,14 @@ public final class UsbAlsaManager { try { // Playback Device if (audioDevice.mHasPlayback) { int device = (audioDevice == mAccessoryAudioDevice ? AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE); int device; if (mIsOutputHeadset) { device = AudioSystem.DEVICE_OUT_USB_HEADSET; } else { device = (audioDevice == mAccessoryAudioDevice ? AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE); } if (DEBUG) { Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) + " addr:" + address + " name:" + audioDevice.getDeviceName()); Loading @@ -197,9 +205,14 @@ public final class UsbAlsaManager { // Capture Device if (audioDevice.mHasCapture) { int device = (audioDevice == mAccessoryAudioDevice ? AudioSystem.DEVICE_IN_USB_ACCESSORY : AudioSystem.DEVICE_IN_USB_DEVICE); int device; if (mIsInputHeadset) { device = AudioSystem.DEVICE_IN_USB_HEADSET; } else { device = (audioDevice == mAccessoryAudioDevice ? AudioSystem.DEVICE_IN_USB_ACCESSORY : AudioSystem.DEVICE_IN_USB_DEVICE); } mAudioService.setWiredDeviceConnectionState( device, state, address, audioDevice.getDeviceName(), TAG); } Loading Loading @@ -343,12 +356,16 @@ public final class UsbAlsaManager { return selectAudioCard(mCardsParser.getDefaultCard()); } /* package */ void usbDeviceAdded(UsbDevice usbDevice) { /* package */ void usbDeviceAdded(UsbDevice usbDevice, boolean isInputHeadset, boolean isOutputHeadset) { if (DEBUG) { Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() + " nm:" + usbDevice.getProductName()); Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() + " nm:" + usbDevice.getProductName()); } mIsInputHeadset = isInputHeadset; mIsOutputHeadset = isOutputHeadset; // Is there an audio interface in there? boolean isAudioDevice = false; Loading
services/usb/java/com/android/server/usb/UsbHostManager.java +9 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.server.usb; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; Loading @@ -32,6 +31,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.usb.descriptors.UsbDescriptorParser; import java.util.ArrayList; import java.util.HashMap; Loading Loading @@ -259,7 +259,14 @@ public class UsbHostManager { getCurrentUserSettings().deviceAttachedForFixedHandler(mNewDevice, usbDeviceConnectionHandler); } mUsbAlsaManager.usbDeviceAdded(mNewDevice); // deviceName is something like: "/dev/bus/usb/001/001" UsbDescriptorParser parser = new UsbDescriptorParser(); if (parser.parseDevice(mNewDevice.getDeviceName())) { Slog.i(TAG, "---- isHeadset[in:" + parser.isInputHeadset() + " , out:" + parser.isOutputHeadset() + "]"); mUsbAlsaManager.usbDeviceAdded(mNewDevice, parser.isInputHeadset(), parser.isOutputHeadset()); } } else { Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded"); } Loading
services/usb/java/com/android/server/usb/descriptors/ByteStream.java 0 → 100644 +189 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.usb.descriptors; import android.annotation.NonNull; /** * @hide * A stream interface wrapping a byte array. Very much like a java.io.ByteArrayInputStream * but with the capability to "back up" in situations where the parser discovers that a * UsbDescriptor has overrun its length. */ public class ByteStream { private static final String TAG = "ByteStream"; /** The byte array being wrapped */ @NonNull private final byte[] mBytes; // this is never null. /** * The index into the byte array to be read next. * This value is altered by reading data out of the stream * (using either the getByte() or unpack*() methods), or alternatively * by explicitly offseting the stream position with either * advance() or reverse(). */ private int mIndex; /* * This member used with resetReadCount() & getReadCount() can be used to determine how many * bytes a UsbDescriptor subclass ACTUALLY reads (as opposed to what its length field says). * using this info, the parser can mark a descriptor as valid or invalid and correct the stream * position with advance() & reverse() to keep from "getting lost" in the descriptor stream. */ private int mReadCount; /** * Create a ByteStream object wrapping the specified byte array. * * @param bytes The byte array containing the raw descriptor information retrieved from * the USB device. * @throws IllegalArgumentException */ public ByteStream(@NonNull byte[] bytes) { if (bytes == null) { throw new IllegalArgumentException(); } mBytes = bytes; } /** * Resets the running count of bytes read so that later we can see how much more has been read. */ public void resetReadCount() { mReadCount = 0; } /** * Retrieves the running count of bytes read from the stream. */ public int getReadCount() { return mReadCount; } /** * @return The value of the next byte in the stream without advancing the stream. * Does not affect the running count as the byte hasn't been "consumed". * @throws IndexOutOfBoundsException */ public byte peekByte() { if (available() > 0) { return mBytes[mIndex + 1]; } else { throw new IndexOutOfBoundsException(); } } /** * @return the next byte from the stream and advances the stream and the read count. Note * that this is a signed byte (as is the case of byte in Java). The user may need to understand * from context if it should be interpreted as an unsigned value. * @throws IndexOutOfBoundsException */ public byte getByte() { if (available() > 0) { mReadCount++; return mBytes[mIndex++]; } else { throw new IndexOutOfBoundsException(); } } /** * Reads 2 bytes in *little endian format* from the stream and composes a 16-bit integer. * As we are storing the 2-byte value in a 4-byte integer, the upper 2 bytes are always * 0, essentially making the returned value *unsigned*. * @return The 16-bit integer (packed into the lower 2 bytes of an int) encoded by the * next 2 bytes in the stream. * @throws IndexOutOfBoundsException */ public int unpackUsbWord() { if (available() >= 2) { int b0 = getByte(); int b1 = getByte(); return ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF); } else { throw new IndexOutOfBoundsException(); } } /** * Reads 3 bytes in *little endian format* from the stream and composes a 24-bit integer. * As we are storing the 3-byte value in a 4-byte integer, the upper byte is always * 0, essentially making the returned value *unsigned*. * @return The 24-bit integer (packed into the lower 3 bytes of an int) encoded by the * next 3 bytes in the stream. * @throws IndexOutOfBoundsException */ public int unpackUsbTriple() { if (available() >= 3) { int b0 = getByte(); int b1 = getByte(); int b2 = getByte(); return ((b2 << 16) & 0x00FF0000) | ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF); } else { throw new IndexOutOfBoundsException(); } } /** * Advances the logical position in the stream. Affects the running count also. * @param numBytes The number of bytes to advance. * @throws IndexOutOfBoundsException * @throws IllegalArgumentException */ public void advance(int numBytes) { if (numBytes < 0) { // Positive offsets only throw new IllegalArgumentException(); } // do arithmetic and comparison in long to ovoid potention integer overflow long longNewIndex = (long) mIndex + (long) numBytes; if (longNewIndex < (long) mBytes.length) { mReadCount += numBytes; mIndex += numBytes; } else { throw new IndexOutOfBoundsException(); } } /** * Reverse the logical position in the stream. Affects the running count also. * @param numBytes The (positive) number of bytes to reverse. * @throws IndexOutOfBoundsException * @throws IllegalArgumentException */ public void reverse(int numBytes) { if (numBytes < 0) { // Positive (reverse) offsets only throw new IllegalArgumentException(); } if (mIndex >= numBytes) { mReadCount -= numBytes; mIndex -= numBytes; } else { throw new IndexOutOfBoundsException(); } } /** * @return The number of bytes available to be read in the stream. */ public int available() { return mBytes.length - mIndex; } }