Loading cmds/hid/jni/com_android_commands_hid_Device.cpp +31 −28 Original line number Diff line number Diff line Loading @@ -27,9 +27,9 @@ #include <cstring> #include <memory> #include <android/log.h> #include <android/looper.h> #include <jni.h> #include <log/log.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedLocalRef.h> #include <nativehelper/ScopedPrimitiveArray.h> Loading @@ -37,10 +37,8 @@ #include <android-base/stringprintf.h> #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) // Log debug messages about the output. static constexpr bool DEBUG_OUTPUT = false; namespace android { namespace uhid { Loading @@ -61,7 +59,7 @@ static int handleLooperEvents(int /* fd */, int events, void* data) { static void checkAndClearException(JNIEnv* env, const char* methodName) { if (env->ExceptionCheck()) { LOGE("An exception was thrown by callback '%s'.", methodName); ALOGE("An exception was thrown by callback '%s'.", methodName); env->ExceptionClear(); } } Loading Loading @@ -115,9 +113,9 @@ void DeviceCallback::onDeviceGetReport(uint32_t requestId, uint8_t reportId) { checkAndClearException(env, "onDeviceGetReport"); } void DeviceCallback::onDeviceOutput(const std::vector<uint8_t>& data) { void DeviceCallback::onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data) { JNIEnv* env = getJNIEnv(); env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, rType, toJbyteArray(env, data).get()); checkAndClearException(env, "onDeviceOutput"); } Loading @@ -133,13 +131,13 @@ std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, std::unique_ptr<DeviceCallback> callback) { size_t size = descriptor.size(); if (size > HID_MAX_DESCRIPTOR_SIZE) { LOGE("Received invalid hid report with descriptor size %zu, skipping", size); ALOGE("Received invalid hid report with descriptor size %zu, skipping", size); return nullptr; } android::base::unique_fd fd(::open(UHID_PATH, O_RDWR | O_CLOEXEC)); if (!fd.ok()) { LOGE("Failed to open uhid: %s", strerror(errno)); ALOGE("Failed to open uhid: %s", strerror(errno)); return nullptr; } Loading @@ -159,14 +157,14 @@ std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, errno = 0; ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev))); if (ret < 0 || ret != sizeof(ev)) { LOGE("Failed to create uhid node: %s", strerror(errno)); ALOGE("Failed to create uhid node: %s", strerror(errno)); return nullptr; } // Wait for the device to actually be created. ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev))); if (ret < 0 || ev.type != UHID_START) { LOGE("uhid node failed to start: %s", strerror(errno)); ALOGE("uhid node failed to start: %s", strerror(errno)); return nullptr; } // using 'new' to access non-public constructor Loading @@ -177,7 +175,7 @@ Device::Device(int32_t id, android::base::unique_fd fd, std::unique_ptr<DeviceCa : mId(id), mFd(std::move(fd)), mDeviceCallback(std::move(callback)) { ALooper* aLooper = ALooper_forThread(); if (aLooper == NULL) { LOGE("Could not get ALooper, ALooper_forThread returned NULL"); ALOGE("Could not get ALooper, ALooper_forThread returned NULL"); aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); } ALooper_addFd(aLooper, mFd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents, Loading @@ -189,7 +187,7 @@ Device::~Device() { if (looper != NULL) { ALooper_removeFd(looper, mFd); } else { LOGE("Could not remove fd, ALooper_forThread() returned NULL!"); ALOGE("Could not remove fd, ALooper_forThread() returned NULL!"); } struct uhid_event ev = {}; ev.type = UHID_DESTROY; Loading @@ -200,13 +198,13 @@ Device::~Device() { static void writeEvent(int fd, struct uhid_event& ev, const char* messageType) { ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev))); if (ret < 0 || ret != sizeof(ev)) { LOGE("Failed to send uhid_event %s: %s", messageType, strerror(errno)); ALOGE("Failed to send uhid_event %s: %s", messageType, strerror(errno)); } } void Device::sendReport(const std::vector<uint8_t>& report) const { if (report.size() > UHID_DATA_MAX) { LOGE("Received invalid report of size %zu, skipping", report.size()); ALOGE("Received invalid report of size %zu, skipping", report.size()); return; } Loading @@ -230,14 +228,14 @@ void Device::sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>& int Device::handleEvents(int events) { if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { LOGE("uhid node was closed or an error occurred. events=0x%x", events); ALOGE("uhid node was closed or an error occurred. events=0x%x", events); mDeviceCallback->onDeviceError(); return 0; } struct uhid_event ev; ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev))); if (ret < 0) { LOGE("Failed to read from uhid node: %s", strerror(errno)); ALOGE("Failed to read from uhid node: %s", strerror(errno)); mDeviceCallback->onDeviceError(); return 0; } Loading @@ -254,23 +252,28 @@ int Device::handleEvents(int events) { case UHID_SET_REPORT: { const struct uhid_set_report_req& set_report = ev.u.set_report; if (set_report.size > UHID_DATA_MAX) { LOGE("SET_REPORT contains too much data: size = %" PRIu16, set_report.size); ALOGE("SET_REPORT contains too much data: size = %" PRIu16, set_report.size); return 0; } std::vector<uint8_t> data(set_report.data, set_report.data + set_report.size); LOGI("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id, if (DEBUG_OUTPUT) { ALOGD("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id, set_report.rnum, toString(data).c_str()); } break; } case UHID_OUTPUT: { struct uhid_output_req& output = ev.u.output; std::vector<uint8_t> data(output.data, output.data + output.size); mDeviceCallback->onDeviceOutput(data); if (DEBUG_OUTPUT) { ALOGD("UHID_OUTPUT rtype=%" PRIu8 " data=%s", output.rtype, toString(data).c_str()); } mDeviceCallback->onDeviceOutput(output.rtype, data); break; } default: { LOGI("Unhandled event type: %" PRIu32, ev.type); ALOGI("Unhandled event type: %" PRIu32, ev.type); break; } } Loading Loading @@ -318,7 +321,7 @@ static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray ra if (d) { d->sendReport(report); } else { LOGE("Could not send report, Device* is null!"); ALOGE("Could not send report, Device* is null!"); } } Loading @@ -329,7 +332,7 @@ static void sendGetFeatureReportReply(JNIEnv* env, jclass /* clazz */, jlong ptr std::vector<uint8_t> report = getData(env, rawReport); d->sendGetFeatureReportReply(id, report); } else { LOGE("Could not send get feature report reply, Device* is null!"); ALOGE("Could not send get feature report reply, Device* is null!"); } } Loading @@ -354,7 +357,7 @@ static JNINativeMethod sMethods[] = { int register_com_android_commands_hid_Device(JNIEnv* env) { jclass clazz = env->FindClass("com/android/commands/hid/Device$DeviceCallback"); if (clazz == NULL) { LOGE("Unable to find class 'DeviceCallback'"); ALOGE("Unable to find class 'DeviceCallback'"); return JNI_ERR; } uhid::gDeviceCallbackClassInfo.onDeviceOpen = Loading @@ -362,12 +365,12 @@ int register_com_android_commands_hid_Device(JNIEnv* env) { uhid::gDeviceCallbackClassInfo.onDeviceGetReport = env->GetMethodID(clazz, "onDeviceGetReport", "(II)V"); uhid::gDeviceCallbackClassInfo.onDeviceOutput = env->GetMethodID(clazz, "onDeviceOutput", "([B)V"); env->GetMethodID(clazz, "onDeviceOutput", "(B[B)V"); uhid::gDeviceCallbackClassInfo.onDeviceError = env->GetMethodID(clazz, "onDeviceError", "()V"); if (uhid::gDeviceCallbackClassInfo.onDeviceOpen == NULL || uhid::gDeviceCallbackClassInfo.onDeviceError == NULL) { LOGE("Unable to obtain onDeviceOpen or onDeviceError methods"); ALOGE("Unable to obtain onDeviceOpen or onDeviceError methods"); return JNI_ERR; } Loading cmds/hid/jni/com_android_commands_hid_Device.h +1 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ public: void onDeviceOpen(); void onDeviceGetReport(uint32_t requestId, uint8_t reportId); void onDeviceOutput(const std::vector<uint8_t>& data); void onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data); void onDeviceError(); private: Loading cmds/hid/src/com/android/commands/hid/Device.java +32 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,12 @@ import android.util.SparseArray; import com.android.internal.os.SomeArgs; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Map; Loading @@ -38,12 +44,16 @@ public class Device { private static final int MSG_SEND_GET_FEATURE_REPORT_REPLY = 3; private static final int MSG_CLOSE_DEVICE = 4; // Sync with linux uhid_event_type::UHID_OUTPUT private static final byte UHID_EVENT_TYPE_UHID_OUTPUT = 6; private final int mId; private final HandlerThread mThread; private final DeviceHandler mHandler; // mFeatureReports is limited to 256 entries, because the report number is 8-bit private final SparseArray<byte[]> mFeatureReports; private final Map<ByteBuffer, byte[]> mOutputs; private final OutputStream mOutputStream; private long mTimeToSend; private final Object mCond = new Object(); Loading @@ -66,6 +76,7 @@ public class Device { mHandler = new DeviceHandler(mThread.getLooper()); mFeatureReports = featureReports; mOutputs = outputs; mOutputStream = System.out; SomeArgs args = SomeArgs.obtain(); args.argi1 = id; args.argi2 = vid; Loading Loading @@ -188,7 +199,27 @@ public class Device { } // native callback public void onDeviceOutput(byte[] data) { public void onDeviceOutput(byte rtype, byte[] data) { JSONObject json = new JSONObject(); try { json.put("eventId", UHID_EVENT_TYPE_UHID_OUTPUT); json.put("deviceId", mId); json.put("reportType", rtype); JSONArray dataArray = new JSONArray(); for (int i = 0; i < data.length; i++) { dataArray.put(data[i] & 0xFF); } json.put("reportData", dataArray); } catch (JSONException e) { throw new RuntimeException("Could not create JSON object ", e); } try { mOutputStream.write(json.toString().getBytes()); mOutputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } if (mOutputs == null) { Log.e(TAG, "Received OUTPUT request, but 'outputs' section is not found"); return; Loading Loading
cmds/hid/jni/com_android_commands_hid_Device.cpp +31 −28 Original line number Diff line number Diff line Loading @@ -27,9 +27,9 @@ #include <cstring> #include <memory> #include <android/log.h> #include <android/looper.h> #include <jni.h> #include <log/log.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedLocalRef.h> #include <nativehelper/ScopedPrimitiveArray.h> Loading @@ -37,10 +37,8 @@ #include <android-base/stringprintf.h> #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) // Log debug messages about the output. static constexpr bool DEBUG_OUTPUT = false; namespace android { namespace uhid { Loading @@ -61,7 +59,7 @@ static int handleLooperEvents(int /* fd */, int events, void* data) { static void checkAndClearException(JNIEnv* env, const char* methodName) { if (env->ExceptionCheck()) { LOGE("An exception was thrown by callback '%s'.", methodName); ALOGE("An exception was thrown by callback '%s'.", methodName); env->ExceptionClear(); } } Loading Loading @@ -115,9 +113,9 @@ void DeviceCallback::onDeviceGetReport(uint32_t requestId, uint8_t reportId) { checkAndClearException(env, "onDeviceGetReport"); } void DeviceCallback::onDeviceOutput(const std::vector<uint8_t>& data) { void DeviceCallback::onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data) { JNIEnv* env = getJNIEnv(); env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, rType, toJbyteArray(env, data).get()); checkAndClearException(env, "onDeviceOutput"); } Loading @@ -133,13 +131,13 @@ std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, std::unique_ptr<DeviceCallback> callback) { size_t size = descriptor.size(); if (size > HID_MAX_DESCRIPTOR_SIZE) { LOGE("Received invalid hid report with descriptor size %zu, skipping", size); ALOGE("Received invalid hid report with descriptor size %zu, skipping", size); return nullptr; } android::base::unique_fd fd(::open(UHID_PATH, O_RDWR | O_CLOEXEC)); if (!fd.ok()) { LOGE("Failed to open uhid: %s", strerror(errno)); ALOGE("Failed to open uhid: %s", strerror(errno)); return nullptr; } Loading @@ -159,14 +157,14 @@ std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, errno = 0; ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev))); if (ret < 0 || ret != sizeof(ev)) { LOGE("Failed to create uhid node: %s", strerror(errno)); ALOGE("Failed to create uhid node: %s", strerror(errno)); return nullptr; } // Wait for the device to actually be created. ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev))); if (ret < 0 || ev.type != UHID_START) { LOGE("uhid node failed to start: %s", strerror(errno)); ALOGE("uhid node failed to start: %s", strerror(errno)); return nullptr; } // using 'new' to access non-public constructor Loading @@ -177,7 +175,7 @@ Device::Device(int32_t id, android::base::unique_fd fd, std::unique_ptr<DeviceCa : mId(id), mFd(std::move(fd)), mDeviceCallback(std::move(callback)) { ALooper* aLooper = ALooper_forThread(); if (aLooper == NULL) { LOGE("Could not get ALooper, ALooper_forThread returned NULL"); ALOGE("Could not get ALooper, ALooper_forThread returned NULL"); aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); } ALooper_addFd(aLooper, mFd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents, Loading @@ -189,7 +187,7 @@ Device::~Device() { if (looper != NULL) { ALooper_removeFd(looper, mFd); } else { LOGE("Could not remove fd, ALooper_forThread() returned NULL!"); ALOGE("Could not remove fd, ALooper_forThread() returned NULL!"); } struct uhid_event ev = {}; ev.type = UHID_DESTROY; Loading @@ -200,13 +198,13 @@ Device::~Device() { static void writeEvent(int fd, struct uhid_event& ev, const char* messageType) { ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev))); if (ret < 0 || ret != sizeof(ev)) { LOGE("Failed to send uhid_event %s: %s", messageType, strerror(errno)); ALOGE("Failed to send uhid_event %s: %s", messageType, strerror(errno)); } } void Device::sendReport(const std::vector<uint8_t>& report) const { if (report.size() > UHID_DATA_MAX) { LOGE("Received invalid report of size %zu, skipping", report.size()); ALOGE("Received invalid report of size %zu, skipping", report.size()); return; } Loading @@ -230,14 +228,14 @@ void Device::sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>& int Device::handleEvents(int events) { if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { LOGE("uhid node was closed or an error occurred. events=0x%x", events); ALOGE("uhid node was closed or an error occurred. events=0x%x", events); mDeviceCallback->onDeviceError(); return 0; } struct uhid_event ev; ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev))); if (ret < 0) { LOGE("Failed to read from uhid node: %s", strerror(errno)); ALOGE("Failed to read from uhid node: %s", strerror(errno)); mDeviceCallback->onDeviceError(); return 0; } Loading @@ -254,23 +252,28 @@ int Device::handleEvents(int events) { case UHID_SET_REPORT: { const struct uhid_set_report_req& set_report = ev.u.set_report; if (set_report.size > UHID_DATA_MAX) { LOGE("SET_REPORT contains too much data: size = %" PRIu16, set_report.size); ALOGE("SET_REPORT contains too much data: size = %" PRIu16, set_report.size); return 0; } std::vector<uint8_t> data(set_report.data, set_report.data + set_report.size); LOGI("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id, if (DEBUG_OUTPUT) { ALOGD("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id, set_report.rnum, toString(data).c_str()); } break; } case UHID_OUTPUT: { struct uhid_output_req& output = ev.u.output; std::vector<uint8_t> data(output.data, output.data + output.size); mDeviceCallback->onDeviceOutput(data); if (DEBUG_OUTPUT) { ALOGD("UHID_OUTPUT rtype=%" PRIu8 " data=%s", output.rtype, toString(data).c_str()); } mDeviceCallback->onDeviceOutput(output.rtype, data); break; } default: { LOGI("Unhandled event type: %" PRIu32, ev.type); ALOGI("Unhandled event type: %" PRIu32, ev.type); break; } } Loading Loading @@ -318,7 +321,7 @@ static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray ra if (d) { d->sendReport(report); } else { LOGE("Could not send report, Device* is null!"); ALOGE("Could not send report, Device* is null!"); } } Loading @@ -329,7 +332,7 @@ static void sendGetFeatureReportReply(JNIEnv* env, jclass /* clazz */, jlong ptr std::vector<uint8_t> report = getData(env, rawReport); d->sendGetFeatureReportReply(id, report); } else { LOGE("Could not send get feature report reply, Device* is null!"); ALOGE("Could not send get feature report reply, Device* is null!"); } } Loading @@ -354,7 +357,7 @@ static JNINativeMethod sMethods[] = { int register_com_android_commands_hid_Device(JNIEnv* env) { jclass clazz = env->FindClass("com/android/commands/hid/Device$DeviceCallback"); if (clazz == NULL) { LOGE("Unable to find class 'DeviceCallback'"); ALOGE("Unable to find class 'DeviceCallback'"); return JNI_ERR; } uhid::gDeviceCallbackClassInfo.onDeviceOpen = Loading @@ -362,12 +365,12 @@ int register_com_android_commands_hid_Device(JNIEnv* env) { uhid::gDeviceCallbackClassInfo.onDeviceGetReport = env->GetMethodID(clazz, "onDeviceGetReport", "(II)V"); uhid::gDeviceCallbackClassInfo.onDeviceOutput = env->GetMethodID(clazz, "onDeviceOutput", "([B)V"); env->GetMethodID(clazz, "onDeviceOutput", "(B[B)V"); uhid::gDeviceCallbackClassInfo.onDeviceError = env->GetMethodID(clazz, "onDeviceError", "()V"); if (uhid::gDeviceCallbackClassInfo.onDeviceOpen == NULL || uhid::gDeviceCallbackClassInfo.onDeviceError == NULL) { LOGE("Unable to obtain onDeviceOpen or onDeviceError methods"); ALOGE("Unable to obtain onDeviceOpen or onDeviceError methods"); return JNI_ERR; } Loading
cmds/hid/jni/com_android_commands_hid_Device.h +1 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ public: void onDeviceOpen(); void onDeviceGetReport(uint32_t requestId, uint8_t reportId); void onDeviceOutput(const std::vector<uint8_t>& data); void onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data); void onDeviceError(); private: Loading
cmds/hid/src/com/android/commands/hid/Device.java +32 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,12 @@ import android.util.SparseArray; import com.android.internal.os.SomeArgs; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Map; Loading @@ -38,12 +44,16 @@ public class Device { private static final int MSG_SEND_GET_FEATURE_REPORT_REPLY = 3; private static final int MSG_CLOSE_DEVICE = 4; // Sync with linux uhid_event_type::UHID_OUTPUT private static final byte UHID_EVENT_TYPE_UHID_OUTPUT = 6; private final int mId; private final HandlerThread mThread; private final DeviceHandler mHandler; // mFeatureReports is limited to 256 entries, because the report number is 8-bit private final SparseArray<byte[]> mFeatureReports; private final Map<ByteBuffer, byte[]> mOutputs; private final OutputStream mOutputStream; private long mTimeToSend; private final Object mCond = new Object(); Loading @@ -66,6 +76,7 @@ public class Device { mHandler = new DeviceHandler(mThread.getLooper()); mFeatureReports = featureReports; mOutputs = outputs; mOutputStream = System.out; SomeArgs args = SomeArgs.obtain(); args.argi1 = id; args.argi2 = vid; Loading Loading @@ -188,7 +199,27 @@ public class Device { } // native callback public void onDeviceOutput(byte[] data) { public void onDeviceOutput(byte rtype, byte[] data) { JSONObject json = new JSONObject(); try { json.put("eventId", UHID_EVENT_TYPE_UHID_OUTPUT); json.put("deviceId", mId); json.put("reportType", rtype); JSONArray dataArray = new JSONArray(); for (int i = 0; i < data.length; i++) { dataArray.put(data[i] & 0xFF); } json.put("reportData", dataArray); } catch (JSONException e) { throw new RuntimeException("Could not create JSON object ", e); } try { mOutputStream.write(json.toString().getBytes()); mOutputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } if (mOutputs == null) { Log.e(TAG, "Received OUTPUT request, but 'outputs' section is not found"); return; Loading