Support for SensorHeadTrackerTest on Hid command
- Added support for SensorHeadTrackerTest. This does not affect other tests used by Hid Command tool.
- Added two new functions setGetReportResponse() and
sendSetReportReply()
Bug: 228319672
Test: atest android.hardware.cts.SensorHeadTrackerTest
Change-Id: I83cfe1f71df57584dac7288ab092164a5c5dea3c
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index 2cda57d..8b8d361 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -18,24 +18,22 @@
#include "com_android_commands_hid_Device.h"
-#include <linux/uhid.h>
-
+#include <android-base/stringprintf.h>
+#include <android/looper.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <unistd.h>
-#include <cstdio>
-#include <cstring>
-#include <memory>
-
-#include <android/looper.h>
#include <jni.h>
+#include <linux/uhid.h>
#include <log/log.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
+#include <unistd.h>
-#include <android-base/stringprintf.h>
+#include <cstdio>
+#include <cstring>
+#include <memory>
// Log debug messages about the output.
static constexpr bool DEBUG_OUTPUT = false;
@@ -109,15 +107,15 @@
void DeviceCallback::onDeviceGetReport(uint32_t requestId, uint8_t reportId) {
JNIEnv* env = getJNIEnv();
- env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceGetReport,
- requestId, reportId);
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceGetReport, requestId,
+ reportId);
checkAndClearException(env, "onDeviceGetReport");
}
-void DeviceCallback::onDeviceSetReport(uint8_t rType,
- const std::vector<uint8_t>& data) {
+void DeviceCallback::onDeviceSetReport(uint32_t id, uint8_t rType,
+ const std::vector<uint8_t>& data) {
JNIEnv* env = getJNIEnv();
- env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceSetReport, rType,
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceSetReport, id, rType,
toJbyteArray(env, data).get());
checkAndClearException(env, "onDeviceSetReport");
}
@@ -236,6 +234,14 @@
writeEvent(mFd, ev, "UHID_GET_REPORT_REPLY");
}
+void Device::sendSetReportReply(uint32_t id, bool success) const {
+ struct uhid_event ev = {};
+ ev.type = UHID_SET_REPORT_REPLY;
+ ev.u.set_report_reply.id = id;
+ ev.u.set_report_reply.err = success ? 0 : EIO;
+ writeEvent(mFd, ev, "UHID_SET_REPORT_REPLY");
+}
+
int Device::handleEvents(int events) {
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
ALOGE("uhid node was closed or an error occurred. events=0x%x", events);
@@ -249,7 +255,6 @@
mDeviceCallback->onDeviceError();
return 0;
}
-
switch (ev.type) {
case UHID_OPEN: {
mDeviceCallback->onDeviceOpen();
@@ -271,7 +276,7 @@
ALOGD("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id,
set_report.rnum, toString(data).c_str());
}
- mDeviceCallback->onDeviceSetReport(set_report.rtype, data);
+ mDeviceCallback->onDeviceSetReport(set_report.id, set_report.rtype, data);
break;
}
case UHID_OUTPUT: {
@@ -347,6 +352,15 @@
}
}
+static void sendSetReportReply(JNIEnv*, jclass /* clazz */, jlong ptr, jint id, jboolean success) {
+ uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
+ if (d) {
+ d->sendSetReportReply(id, success);
+ } else {
+ ALOGE("Could not send set report reply, Device* is null!");
+ }
+}
+
static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
if (d) {
@@ -362,6 +376,7 @@
{"nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport)},
{"nativeSendGetFeatureReportReply", "(JI[B)V",
reinterpret_cast<void*>(sendGetFeatureReportReply)},
+ {"nativeSendSetReportReply", "(JIZ)V", reinterpret_cast<void*>(sendSetReportReply)},
{"nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice)},
};
@@ -376,7 +391,7 @@
uhid::gDeviceCallbackClassInfo.onDeviceGetReport =
env->GetMethodID(clazz, "onDeviceGetReport", "(II)V");
uhid::gDeviceCallbackClassInfo.onDeviceSetReport =
- env->GetMethodID(clazz, "onDeviceSetReport", "(B[B)V");
+ env->GetMethodID(clazz, "onDeviceSetReport", "(IB[B)V");
uhid::gDeviceCallbackClassInfo.onDeviceOutput =
env->GetMethodID(clazz, "onDeviceOutput", "(B[B)V");
uhid::gDeviceCallbackClassInfo.onDeviceError =
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
index d10a9aa..9c6060d 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.h
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-#include <memory>
-#include <vector>
-
+#include <android-base/unique_fd.h>
#include <jni.h>
-#include <android-base/unique_fd.h>
+#include <memory>
+#include <vector>
namespace android {
namespace uhid {
@@ -31,7 +30,7 @@
void onDeviceOpen();
void onDeviceGetReport(uint32_t requestId, uint8_t reportId);
- void onDeviceSetReport(uint8_t rType, const std::vector<uint8_t>& data);
+ void onDeviceSetReport(uint32_t id, uint8_t rType, const std::vector<uint8_t>& data);
void onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data);
void onDeviceError();
@@ -50,9 +49,9 @@
~Device();
void sendReport(const std::vector<uint8_t>& report) const;
+ void sendSetReportReply(uint32_t id, bool success) const;
void sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>& report) const;
void close();
-
int handleEvents(int events);
private:
diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java
index 95b1e9a..0415037 100644
--- a/cmds/hid/src/com/android/commands/hid/Device.java
+++ b/cmds/hid/src/com/android/commands/hid/Device.java
@@ -42,7 +42,8 @@
private static final int MSG_OPEN_DEVICE = 1;
private static final int MSG_SEND_REPORT = 2;
private static final int MSG_SEND_GET_FEATURE_REPORT_REPLY = 3;
- private static final int MSG_CLOSE_DEVICE = 4;
+ private static final int MSG_SEND_SET_REPORT_REPLY = 4;
+ private static final int MSG_CLOSE_DEVICE = 5;
// Sync with linux uhid_event_type::UHID_OUTPUT
private static final byte UHID_EVENT_TYPE_UHID_OUTPUT = 6;
@@ -56,21 +57,45 @@
private final Map<ByteBuffer, byte[]> mOutputs;
private final OutputStream mOutputStream;
private long mTimeToSend;
-
private final Object mCond = new Object();
+ /**
+ * The report id of the report received in UHID_EVENT_TYPE_SET_REPORT.
+ * Used for SET_REPORT_REPLY.
+ * This field gets overridden each time SET_REPORT is received.
+ */
+ private int mResponseId;
static {
System.loadLibrary("hidcommand_jni");
}
- private static native long nativeOpenDevice(String name, int id, int vid, int pid, int bus,
- byte[] descriptor, DeviceCallback callback);
+ private static native long nativeOpenDevice(
+ String name,
+ int id,
+ int vid,
+ int pid,
+ int bus,
+ byte[] descriptor,
+ DeviceCallback callback);
+
private static native void nativeSendReport(long ptr, byte[] data);
+
private static native void nativeSendGetFeatureReportReply(long ptr, int id, byte[] data);
+
+ private static native void nativeSendSetReportReply(long ptr, int id, boolean success);
+
private static native void nativeCloseDevice(long ptr);
- public Device(int id, String name, int vid, int pid, int bus, byte[] descriptor,
- byte[] report, SparseArray<byte[]> featureReports, Map<ByteBuffer, byte[]> outputs) {
+ public Device(
+ int id,
+ String name,
+ int vid,
+ int pid,
+ int bus,
+ byte[] descriptor,
+ byte[] report,
+ SparseArray<byte[]> featureReports,
+ Map<ByteBuffer, byte[]> outputs) {
mId = id;
mThread = new HandlerThread("HidDeviceHandler");
mThread.start();
@@ -100,6 +125,17 @@
mHandler.sendMessageAtTime(msg, mTimeToSend);
}
+ public void setGetReportResponse(byte[] report) {
+ mFeatureReports.put(report[0], report);
+ }
+
+ public void sendSetReportReply(boolean success) {
+ Message msg =
+ mHandler.obtainMessage(MSG_SEND_SET_REPORT_REPLY, mResponseId, success ? 1 : 0);
+
+ mHandler.sendMessageAtTime(msg, mTimeToSend);
+ }
+
public void addDelay(int delay) {
mTimeToSend = Math.max(SystemClock.uptimeMillis(), mTimeToSend) + delay;
}
@@ -111,7 +147,8 @@
synchronized (mCond) {
mCond.wait();
}
- } catch (InterruptedException ignore) {}
+ } catch (InterruptedException ignore) {
+ }
}
private class DeviceHandler extends Handler {
@@ -127,8 +164,15 @@
switch (msg.what) {
case MSG_OPEN_DEVICE:
SomeArgs args = (SomeArgs) msg.obj;
- mPtr = nativeOpenDevice((String) args.arg1, args.argi1, args.argi2, args.argi3,
- args.argi4, (byte[]) args.arg2, new DeviceCallback());
+ mPtr =
+ nativeOpenDevice(
+ (String) args.arg1,
+ args.argi1,
+ args.argi2,
+ args.argi3,
+ args.argi4,
+ (byte[]) args.arg2,
+ new DeviceCallback());
pauseEvents();
break;
case MSG_SEND_REPORT:
@@ -145,6 +189,14 @@
Log.e(TAG, "Tried to send feature report reply to closed device.");
}
break;
+ case MSG_SEND_SET_REPORT_REPLY:
+ if (mPtr != 0) {
+ final boolean success = msg.arg2 == 1;
+ nativeSendSetReportReply(mPtr, msg.arg1, success);
+ } else {
+ Log.e(TAG, "Tried to send set report reply to closed device.");
+ }
+ break;
case MSG_CLOSE_DEVICE:
if (mPtr != 0) {
nativeCloseDevice(mPtr);
@@ -173,14 +225,18 @@
}
private class DeviceCallback {
+
public void onDeviceOpen() {
mHandler.resumeEvents();
}
public void onDeviceGetReport(int requestId, int reportId) {
if (mFeatureReports == null) {
- Log.e(TAG, "Received GET_REPORT request for reportId=" + reportId
- + ", but 'feature_reports' section is not found");
+ Log.e(
+ TAG,
+ "Received GET_REPORT request for reportId="
+ + reportId
+ + ", but 'feature_reports' section is not found");
return;
}
byte[] report = mFeatureReports.get(reportId);
@@ -220,14 +276,15 @@
} catch (IOException e) {
throw new RuntimeException(e);
}
-
}
// native callback
- public void onDeviceSetReport(byte rtype, byte[] data) {
+ public void onDeviceSetReport(int id, byte rType, byte[] data) {
+ // Used by sendSetReportReply()
+ mResponseId = id;
// We don't need to reply for the SET_REPORT but just send it to HID output for test
// verification.
- sendReportOutput(UHID_EVENT_TYPE_SET_REPORT, rtype, data);
+ sendReportOutput(UHID_EVENT_TYPE_SET_REPORT, rType, data);
}
// native callback
@@ -239,7 +296,8 @@
}
byte[] response = mOutputs.get(ByteBuffer.wrap(data));
if (response == null) {
- Log.i(TAG,
+ Log.i(
+ TAG,
"Requested response for output " + Arrays.toString(data) + " is not found");
return;
}
diff --git a/cmds/hid/src/com/android/commands/hid/Event.java b/cmds/hid/src/com/android/commands/hid/Event.java
index d4bf1d8..3efb797 100644
--- a/cmds/hid/src/com/android/commands/hid/Event.java
+++ b/cmds/hid/src/com/android/commands/hid/Event.java
@@ -35,6 +35,8 @@
public static final String COMMAND_REGISTER = "register";
public static final String COMMAND_DELAY = "delay";
public static final String COMMAND_REPORT = "report";
+ public static final String COMMAND_SET_GET_REPORT_RESPONSE = "set_get_report_response";
+ public static final String COMMAND_SEND_SET_REPORT_REPLY = "send_set_report_reply";
// These constants come from "include/uapi/linux/input.h" in the kernel
enum Bus {
@@ -62,6 +64,7 @@
private SparseArray<byte[]> mFeatureReports;
private Map<ByteBuffer, byte[]> mOutputs;
private int mDuration;
+ private Boolean mReply;
public int getId() {
return mId;
@@ -107,6 +110,10 @@
return mDuration;
}
+ public Boolean getReply() {
+ return mReply;
+ }
+
public String toString() {
return "Event{id=" + mId
+ ", command=" + String.valueOf(mCommand)
@@ -119,6 +126,7 @@
+ ", feature_reports=" + mFeatureReports.toString()
+ ", outputs=" + mOutputs.toString()
+ ", duration=" + mDuration
+ + ", success=" + mReply.toString()
+ "}";
}
@@ -173,6 +181,10 @@
mEvent.mDuration = duration;
}
+ public void setReply(boolean success) {
+ mEvent.mReply = success;
+ }
+
public Event build() {
if (mEvent.mId == -1) {
throw new IllegalStateException("No event id");
@@ -183,6 +195,16 @@
if (mEvent.mDescriptor == null) {
throw new IllegalStateException("Device registration is missing descriptor");
}
+ }
+ if (COMMAND_SET_GET_REPORT_RESPONSE.equals(mEvent.mCommand)) {
+ if (mEvent.mReport == null) {
+ throw new IllegalStateException("Report command is missing response data");
+ }
+ }
+ if (COMMAND_SEND_SET_REPORT_REPLY.equals(mEvent.mCommand)) {
+ if (mEvent.mReply == null) {
+ throw new IllegalStateException("Reply command is missing reply");
+ }
} else if (COMMAND_DELAY.equals(mEvent.mCommand)) {
if (mEvent.mDuration <= 0) {
throw new IllegalStateException("Delay has missing or invalid duration");
@@ -246,6 +268,9 @@
case "duration":
eb.setDuration(readInt());
break;
+ case "success":
+ eb.setReply(readBool());
+ break;
default:
mReader.skipValue();
}
@@ -292,6 +317,11 @@
return Integer.decode(val);
}
+ private boolean readBool() throws IOException {
+ String val = mReader.nextString();
+ return Boolean.parseBoolean(val);
+ }
+
private Bus readBus() throws IOException {
String val = mReader.nextString();
return Bus.valueOf(val.toUpperCase());
diff --git a/cmds/hid/src/com/android/commands/hid/Hid.java b/cmds/hid/src/com/android/commands/hid/Hid.java
index fac0ab2..2db791fe 100644
--- a/cmds/hid/src/com/android/commands/hid/Hid.java
+++ b/cmds/hid/src/com/android/commands/hid/Hid.java
@@ -93,6 +93,10 @@
d.addDelay(e.getDuration());
} else if (Event.COMMAND_REPORT.equals(e.getCommand())) {
d.sendReport(e.getReport());
+ } else if (Event.COMMAND_SET_GET_REPORT_RESPONSE.equals(e.getCommand())) {
+ d.setGetReportResponse(e.getReport());
+ } else if (Event.COMMAND_SEND_SET_REPORT_REPLY.equals(e.getCommand())) {
+ d.sendSetReportReply(e.getReply());
} else {
if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
error("Device id=" + e.getId() + " is already registered. Ignoring event.");