Skip to content

Commit

Permalink
add remote ioctl request
Browse files Browse the repository at this point in the history
  • Loading branch information
cinit committed Dec 30, 2021
1 parent 9cd03ee commit 1bff5d8
Show file tree
Hide file tree
Showing 18 changed files with 236 additions and 43 deletions.
4 changes: 2 additions & 2 deletions app/src/main/cpp/libnciclient/NciHostDaemonProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ TypedLpcResult<int> NciHostDaemonProxy::deviceDriverWriteRawBuffer(const std::ve
return invokeRemoteProcedure<int, const std::vector<uint8_t> &>(Ids::deviceDriverWriteRawBuffer, buffer);
}

TypedLpcResult<int> NciHostDaemonProxy::deviceDriverIoctl0(uint64_t request, uint64_t arg) {
return invokeRemoteProcedure<int, const uint64_t &, const uint64_t &>(Ids::deviceDriverIoctl0, request, arg);
TypedLpcResult<int> NciHostDaemonProxy::deviceDriverIoctl0(uint32_t request, uint64_t arg) {
return invokeRemoteProcedure<int, const uint32_t &, const uint64_t &>(Ids::deviceDriverIoctl0, request, arg);
}

TypedLpcResult<bool> NciHostDaemonProxy::isAndroidNfcServiceConnected() {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/cpp/libnciclient/NciHostDaemonProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class NciHostDaemonProxy : public INciHostDaemon, public BaseIpcProxy {

TypedLpcResult<int> deviceDriverWriteRawBuffer(const std::vector<uint8_t> &buffer) override;

TypedLpcResult<int> deviceDriverIoctl0(uint64_t request, uint64_t arg) override;
TypedLpcResult<int> deviceDriverIoctl0(uint32_t request, uint64_t arg) override;

TypedLpcResult<bool> isAndroidNfcServiceConnected() override;

Expand Down
6 changes: 3 additions & 3 deletions app/src/main/cpp/libnciclient/ipc_handle_jni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -798,19 +798,19 @@ Java_cc_ioctl_nfcdevicehost_ipc_daemon_internal_NciHostDaemonProxy_deviceDriverW
/*
* Class: cc_ioctl_nfcdevicehost_ipc_daemon_internal_NciHostDaemonProxy
* Method: deviceDriverIoctl0
* Signature: (JJ)I
* Signature: (IJ)I
*/
extern "C" [[maybe_unused]] JNIEXPORT jint JNICALL
Java_cc_ioctl_nfcdevicehost_ipc_daemon_internal_NciHostDaemonProxy_deviceDriverIoctl0
(JNIEnv *env, jobject, jlong request, jlong arg) {
(JNIEnv *env, jobject, jint request, jlong arg) {
IpcConnector &connector = IpcConnector::getInstance();
INciHostDaemon *proxy = connector.getNciDaemon();
if (proxy == nullptr) {
env->ThrowNew(env->FindClass("java/lang/IllegalStateException"),
"attempt to transact while proxy object not available");
return 0;
} else {
if (auto lpcResult = proxy->deviceDriverIoctl0(uint64_t(request), uint64_t(arg));
if (auto lpcResult = proxy->deviceDriverIoctl0(uint32_t(request), uint64_t(arg));
!jniThrowLpcResultErrorOrException(env, lpcResult)) {
int r;
if (lpcResult.getResult(&r)) {
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/cpp/libnciclient/ipc_handle_jni.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions app/src/main/cpp/ncihostd/service/front/NciHostDaemonImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ bool NciHostDaemonImpl::dispatchLpcInvocation([[maybe_unused]] const IpcTransact
return true;
}
case Ids::deviceDriverIoctl0: {
result = R::invoke(this, args, R::is(+[](T *p, uint64_t req, uint64_t arg) {
result = R::invoke(this, args, R::is(+[](T *p, uint32_t req, uint64_t arg) {
return p->deviceDriverIoctl0(req, arg);
}));
return true;
Expand Down Expand Up @@ -448,7 +448,7 @@ TypedLpcResult<int> NciHostDaemonImpl::deviceDriverWriteRawBuffer(const std::vec
}
}

TypedLpcResult<int> NciHostDaemonImpl::deviceDriverIoctl0(uint64_t request, uint64_t arg) {
TypedLpcResult<int> NciHostDaemonImpl::deviceDriverIoctl0(uint32_t request, uint64_t arg) {
auto sp = NxpHalHandler::getWeakInstance();
NxpHalHandler *handler;
if (auto p = sp.get(); p != nullptr && (handler = dynamic_cast<NxpHalHandler *>(p))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class NciHostDaemonImpl : public INciHostDaemon, public BaseIpcObject {

TypedLpcResult<int> deviceDriverWriteRawBuffer(const std::vector<uint8_t> &buffer) override;

TypedLpcResult<int> deviceDriverIoctl0(uint64_t request, uint64_t arg) override;
TypedLpcResult<int> deviceDriverIoctl0(uint32_t request, uint64_t arg) override;

TypedLpcResult<bool> isAndroidNfcServiceConnected() override;

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/cpp/ncihostd/service/hw/BaseHwHalHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class BaseHwHalHandler : public IBaseService {

[[nodiscard]] virtual int driverRawWrite(const std::vector<uint8_t> &buffer) = 0;

[[nodiscard]] virtual int driverRawIoctl0(uint64_t request, uint64_t arg) = 0;
[[nodiscard]] virtual int driverRawIoctl0(uint32_t request, uint64_t arg) = 0;

void stopSelf();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ int NxpHalHandler::driverRawWrite(const std::vector<uint8_t> &buffer) {
return int(response.result);
}

int NxpHalHandler::driverRawIoctl0(uint64_t request, uint64_t arg) {
int NxpHalHandler::driverRawIoctl0(uint32_t request, uint64_t arg) {
HalRequest requestPacket = {};
requestPacket.requestCode = static_cast<uint32_t>(RequestId::DEVICE_OPERATION_IOCTL0);
DeviceIoctl0Request requestPayload = {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class NxpHalHandler : public BaseHwHalHandler {

[[nodiscard]] int driverRawWrite(const std::vector<uint8_t> &buffer) override;

[[nodiscard]] int driverRawIoctl0(uint64_t request, uint64_t arg) override;
[[nodiscard]] int driverRawIoctl0(uint32_t request, uint64_t arg) override;

[[nodiscard]] static HwServiceStatus getHwServiceStatus();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ std::shared_ptr<IBaseService> QtiEsePmHandler::getWeakInstance() {
return sWpInstance.lock();
}

int QtiEsePmHandler::driverRawIoctl0(uint64_t request, uint64_t arg) {
int QtiEsePmHandler::driverRawIoctl0(uint32_t request, uint64_t arg) {
return -ENOTSUP;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class QtiEsePmHandler : public BaseHwHalHandler {

[[nodiscard]] int initRemotePltHook(const OriginHookProcedure &hookProc);

int driverRawIoctl0(uint64_t request, uint64_t arg) override;
int driverRawIoctl0(uint32_t request, uint64_t arg) override;

int driverRawWrite(const std::vector<uint8_t> &buffer) override;

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/cpp/rpcprotocol/INciHostDaemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class INciHostDaemon {
virtual TypedLpcResult<int> deviceDriverWriteRawBuffer(const std::vector<uint8_t> &buffer) = 0;

[[nodiscard]]
virtual TypedLpcResult<int> deviceDriverIoctl0(uint64_t request, uint64_t arg) = 0;
virtual TypedLpcResult<int> deviceDriverIoctl0(uint32_t request, uint64_t arg) = 0;

[[nodiscard]]
virtual TypedLpcResult<bool> isAndroidNfcServiceConnected() = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Locale;

import cc.ioctl.nfcdevicehost.R;
import cc.ioctl.nfcdevicehost.decoder.IoctlDecoder;
import cc.ioctl.nfcdevicehost.decoder.NciPacketDecoder;
import cc.ioctl.nfcdevicehost.decoder.NxpHalV2EventTranslator;
import cc.ioctl.nfcdevicehost.ipc.daemon.INciHostDaemon;
Expand Down Expand Up @@ -88,10 +89,16 @@ protected void updateListViewItemForAuxIoEvent(@NonNull NciDumpViewHolder holder
case IOCTL: {
sb.append(String.format(Locale.ROOT, "ioctl(%d, 0x%x, 0x%x)=%d",
event.fd, event.directArg1, event.directArg2, event.retValue));
sb.append('\n');
String name = IoctlDecoder.getIoctlRequestName((int) event.directArg1);
if (name != null) {
sb.append(name).append(' ');
}
sb.append(IoctlDecoder.requestToString((int) event.directArg1));
break;
}
case SELECT: {
sb.append(String.format(Locale.ROOT, "select(%d)=%d", event.fd, event.retValue));
sb.append(String.format(Locale.ROOT, "select(...)=%d", event.retValue));
break;
}
default: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,40 +36,106 @@ protected View createRootView(@NonNull LayoutInflater inflater, @Nullable ViewGr
mBinding.halOperationButtonSubmit.setOnClickListener(v -> submitOperation());
mBinding.halOperationButtonClose.setOnClickListener(v -> dismiss());
mBinding.halOperationSpinnerSyscallType.setAdapter(new ArrayAdapter<>(requireContext(),
R.layout.item_spinner_text, R.id.item_spinner_item_textView, new String[]{"WRITE"}));
R.layout.item_spinner_text, R.id.item_spinner_item_textView, new String[]{"WRITE", "IOCTL"}));
mBinding.halOperationSpinnerSyscallType.setOnItemSelectedListener(this);
mBinding.halOperationSpinnerSyscallType.setSelection(0);
return mBinding.getRoot();
}

@UiThread
private void submitOperation() {
String input = mBinding.halOperationEditTextWritePayload.getText().toString();
String[] inputSplit = input.split("[,\n, |-]");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
for (String s : inputSplit) {
if (s.isEmpty()) {
continue;
int operationPos = mBinding.halOperationSpinnerSyscallType.getSelectedItemPosition();
if (operationPos == 0) {
// write
String input = mBinding.halOperationEditTextWritePayload.getText().toString();
String[] inputSplit = input.split("[,\n, |-]");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
for (String s : inputSplit) {
if (s.isEmpty()) {
continue;
}
int value = Integer.parseInt(s, 16);
baos.write(value);
}
int value = Integer.parseInt(s, 16);
baos.write(value);
} catch (NumberFormatException e) {
new AlertDialog.Builder(requireContext())
.setTitle(R.string.ui_dialog_error_title)
.setMessage(requireContext().getString(R.string.ui_dialog_error_message_invalid_input_syntax_v0s, e.getMessage()))
.setCancelable(true)
.setPositiveButton(android.R.string.ok, null)
.show();
return;
}
byte[] bytes = baos.toByteArray();
if (bytes.length > 0) {
INciHostDaemon daemon = IpcNativeHandler.peekConnection();
if (daemon != null && daemon.isHwServiceConnected()) {
ThreadManager.async(() -> {
try {
int result = daemon.deviceDriverWriteRaw(bytes);
ThreadManager.runOnUiThread(() -> {
if (result < 0) {
String errMsg = Errno.getErrnoString(result);
if (errMsg == null) {
errMsg = "Unknown error: " + result;
}
String finalErrMsg = errMsg;
ThreadManager.runOnUiThread(() -> new AlertDialog.Builder(requireContext())
.setTitle(R.string.ui_dialog_error_title)
.setMessage(finalErrMsg)
.setCancelable(true)
.setPositiveButton(android.R.string.ok, null)
.show());
} else {
dismiss();
Snackbar.make(requireActivity().getWindow().getDecorView(),
requireContext().getString(R.string.ui_toast_operation_success_v0d, result),
Snackbar.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
ThreadManager.runOnUiThread(() -> new AlertDialog.Builder(requireContext())
.setTitle(R.string.ui_dialog_error_title)
.setMessage(e.getMessage())
.setCancelable(true)
.setPositiveButton(android.R.string.ok, null)
.show());
}
});
} else {
new AlertDialog.Builder(requireContext())
.setTitle(R.string.ui_dialog_error_title)
.setMessage(R.string.ui_toast_hal_service_not_attached)
.setCancelable(true)
.setPositiveButton(android.R.string.ok, null)
.show();
dismiss();
}
}
} else if (operationPos == 1) {
// ioctl
String requestStr = mBinding.halOperationEditTextIoctlRequest.getText().toString();
String argStr = mBinding.halOperationEditTextIoctlArg.getText().toString();
int requestValue;
long argValue;
try {
requestValue = Integer.parseUnsignedInt(requestStr, 16);
argValue = Long.parseUnsignedLong(argStr, 16);
} catch (NumberFormatException e) {
new AlertDialog.Builder(requireContext())
.setTitle(R.string.ui_dialog_error_title)
.setMessage(requireContext().getString(R.string.ui_dialog_error_message_invalid_input_syntax_v0s, e.getMessage()))
.setCancelable(true)
.setPositiveButton(android.R.string.ok, null)
.show();
return;
}
} catch (NumberFormatException e) {
new AlertDialog.Builder(requireContext())
.setTitle(R.string.ui_dialog_error_title)
.setMessage(requireContext().getString(R.string.ui_dialog_error_message_invalid_input_syntax_v0s, e.getMessage()))
.setCancelable(true)
.setPositiveButton(android.R.string.ok, null)
.show();
return;
}
byte[] bytes = baos.toByteArray();
if (bytes.length > 0) {
INciHostDaemon daemon = IpcNativeHandler.peekConnection();
if (daemon != null && daemon.isHwServiceConnected()) {
ThreadManager.async(() -> {
try {
int result = daemon.deviceDriverWriteRaw(bytes);
int result = daemon.deviceDriverIoctl0(requestValue, argValue);
ThreadManager.runOnUiThread(() -> {
if (result < 0) {
String errMsg = Errno.getErrnoString(result);
Expand Down Expand Up @@ -113,7 +179,15 @@ private void submitOperation() {

@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

if (id == 0) {
// write
mBinding.halOperationLinearLayoutWrite.setVisibility(View.VISIBLE);
mBinding.halOperationLinearLayoutIoctl.setVisibility(View.GONE);
} else if (id == 1) {
// ioctl
mBinding.halOperationLinearLayoutWrite.setVisibility(View.GONE);
mBinding.halOperationLinearLayoutIoctl.setVisibility(View.VISIBLE);
}
}

@Override
Expand Down
81 changes: 81 additions & 0 deletions app/src/main/java/cc/ioctl/nfcdevicehost/decoder/IoctlDecoder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package cc.ioctl.nfcdevicehost.decoder;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

public class IoctlDecoder {

@NonNull
public static String requestToString(int request) {
int dir = (request >> 30) & 0x3;
int size = (request >> 16) & 0x3f;
int type = (request >> 8) & 0xff;
int nr = request & 0xff;
String dirStr;
switch (dir) {
case 0:
dirStr = "IO";
break;
case 1:
dirStr = "IOW";
break;
case 2:
dirStr = "IOR";
break;
case 3:
dirStr = "IOWR";
break;
default:
// should never happen
throw new IllegalArgumentException("Invalid direction");
}
String nrStr = nr < 10 ? String.valueOf(nr) : String.format(Locale.ROOT, "0x%02X", nr);
return (dir == 0 && size == 0) ? String.format(Locale.ROOT, "%s(0x%02X, %s)", dirStr, type, nrStr)
: String.format(Locale.ROOT, "%s(0x%02X, %s, %d)", dirStr, type, nrStr, size);
}

@Nullable
public static String getIoctlRequestName(int request) {
return IOCTL_NAMES.get(request);
}

public static int IO(int type, int nr) {
return (0 << 30) | (0 << 16) | (type << 8) | nr;
}

public static int IOW(int type, int nr, int size) {
return (1 << 30) | (size << 16) | (type << 8) | nr;
}

public static int IOR(int type, int nr, int size) {
return (2 << 30) | (size << 16) | (type << 8) | nr;
}

public static int IOWR(int type, int nr, int size) {
return (3 << 30) | (size << 16) | (type << 8) | nr;
}

private static final Map<Integer, String> IOCTL_NAMES = new HashMap<>();

static {
// /dev/nq-nci
IOCTL_NAMES.put(IOW(0xE9, 0x01, 0x04), "NFC_SET_PWR");
IOCTL_NAMES.put(IOW(0xE9, 0x02, 0x04), "ESE_SET_PWR");
IOCTL_NAMES.put(IOR(0xE9, 0x03, 0x04), "ESE_GET_PWR");
IOCTL_NAMES.put(IO(0xE9, 0x04), "NFC_GET_PLATFORM_TYPE");
IOCTL_NAMES.put(IOW(0xE9, 0x05, 4), "NFC_GET_IRQ_STATE");
// /dev/assd
IOCTL_NAMES.put(IO('A', 0x00), "ASSD_IOC_ENABLE");
IOCTL_NAMES.put(IOWR('A', 0x01, 4), "ASSD_IOC_TRANSCEIVE");
IOCTL_NAMES.put(IOWR('A', 0x01, 8), "ASSD_IOC_TRANSCEIVE");
IOCTL_NAMES.put(IO('A', 0x02), "ASSD_IOC_PROBE");
IOCTL_NAMES.put(IOW('A', 0x03, 4), "ASSD_IOC_WAIT");
IOCTL_NAMES.put(IOWR('A', 0x04, 4), "ASSD_IOC_SET_TIMEOUT");
IOCTL_NAMES.put(IOR('A', 0x05, 4), "ASSD_IOC_GET_VERSION");
IOCTL_NAMES.put(IOR('A', 0x05, 8), "ASSD_IOC_GET_VERSION");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public interface INciHostDaemon {

int deviceDriverWriteRaw(@NonNull byte[] data);

int deviceDriverIoctl0(long request, long arg);
int deviceDriverIoctl0(int request, long arg);

boolean isAndroidNfcServiceConnected();

Expand Down
Loading

0 comments on commit 1bff5d8

Please sign in to comment.