【问题标题】:How to implement file operations to otg using JNI?如何使用JNI实现对otg的文件操作?
【发布时间】:2017-06-07 22:06:42
【问题描述】:

我需要对连接到我的安卓手机的 USB 设备执行文件操作。权限应由android java代码授予,文件操作应使用JNI执行。目前我无法授予执行文件操作的权限 - 我收到 EACCESS:Permission denied 错误

我在这里附上了我的代码:

public class MainActivity extends AppCompatActivity {

private UsbAccessory accessory;
private String TAG = "TAG";
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
private PendingIntent mPermissionIntent;
private UsbManager manager;
private UsbDeviceConnection connection;
private HashMap<Integer, Integer> connectedDevices;
TextView tv;



// Used to load the 'native-lib' library on application startup.
static {
    System.loadLibrary("native-lib");
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Example of a call to a native method
    tv = (TextView) findViewById(R.id.sample_text);
   // tv.setText(stringFromJNI());

    connectedDevices = new HashMap<Integer, Integer>();

    manager = (UsbManager) getSystemService(Context.USB_SERVICE);

    registerReceiver(usbManagerBroadcastReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED));
    registerReceiver(usbManagerBroadcastReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED));
    registerReceiver(usbManagerBroadcastReceiver, new IntentFilter(ACTION_USB_PERMISSION));

    mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);

    /*String str = ndkopenfile();
    tv.setText(str);*/

    final Handler handler = new Handler();

    handler.postDelayed(new Runnable()
    {
        @Override
        public void run()
        {
            checkForDevices();
        }
    }, 1000);
}

/**
 * A native method that is implemented by the 'native-lib' native library,
 * which is packaged with this application.
 */

// public native String stringFromJNI();

@Override
public void onDestroy()
{
    super.onDestroy();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);
}

// private static native void notifyDeviceAttached(int fd);
 //private static native void notifyDeviceDetached(int fd);

public  native String ndkopenfile();

private final BroadcastReceiver usbManagerBroadcastReceiver = new BroadcastReceiver()
{
    public void onReceive(Context context, Intent intent)
    {
        try
        {
            String action = intent.getAction();

            Log.d(TAG, "INTENT ACTION: " + action);

            if (ACTION_USB_PERMISSION.equals(action))
            {
                Log.d(TAG, "onUsbPermission");

                synchronized (this)
                {
                    UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
                    {
                        if(device != null)
                        {


                          /*  int fd = connectToDevice(device);
                            Log.d(TAG,"device file descriptor: " + fd);
                           // notifyDeviceAttached(fd);
                            String str = ndkopenfile();
                            tv.setText(str);*/

                          writetofile();
                        }
                    }
                    else
                    {
                        Log.d(TAG, "permission denied for device " + device);
                    }
                }
            }

            if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action))
            {
                Log.d(TAG, "onDeviceConnected");

                synchronized(this)
                {
                    UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                    if (device != null)
                    {
                        manager.requestPermission(device, mPermissionIntent);
                    }
                }
            }

            if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action))
            {
                Log.d(TAG, "onDeviceDisconnected");

                synchronized(this)
                {
                    UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                    int fd = connectedDevices.get(device.getDeviceId());

                    Log.d(TAG, "device: " + device.getDeviceId() + " disconnected. fd: " + fd);

                   // notifyDeviceDetached(fd);

                    connectedDevices.remove(device.getDeviceId());
                }
            }
        }
        catch(Exception e)
        {
            Log.d(TAG, "Exception: " + e);
        }
    }


};

private void writetofile() {

   // File file = new File("/storage/9E6D-8A07/COMMWR");

    try {
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(openFileOutput("/storage/9E6D-8A07/COMMWR", Context.MODE_PRIVATE));
        outputStreamWriter.write("Hello");
        outputStreamWriter.close();
    }
    catch (IOException e) {
        Log.e("Exception", "File write failed: " + e.toString());
    }

}

private int connectToDevice(UsbDevice device)
{
    connection = manager.openDevice(device);
    // if we make this, kernel driver will be disconnected
    connection.claimInterface(device.getInterface(0), true);

    Log.d(TAG, "inserting device with id: " + device.getDeviceId() + " and file descriptor: " + connection.getFileDescriptor());
    connectedDevices.put(device.getDeviceId(), connection.getFileDescriptor());

    return connection.getFileDescriptor();
}

private void checkForDevices()
{
    HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
    Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();

    while(deviceIterator.hasNext())
    {
        UsbDevice device = deviceIterator.next();

           /* if (device.getVendorId()==VID && device.getProductId()==PID)
            {
                Log.d(TAG, "Found a device: " + device);

                manager.requestPermission(device, mPermissionIntent);
            }*/

        Log.d(TAG, "Found a device: " + device);

        manager.requestPermission(device, mPermissionIntent);
    }
}

}

JNI 代码:

#include <jni.h>
#include <string.h>
#include <stdio.h>

extern "C"
JNIEXPORT jstring JNICALL
Java_nrrsmdm_com_myapplication_MainActivity_ndkopenfile
        (JNIEnv *env, jobject obj)
{
    int errno = 0;
    char myStr[20];
    FILE* fp = fopen("/storage/9E6D-8A07/COMMWR","w+");
    if(fp!=NULL)
    {
        fputs("HELLO WORLD!\n", fp);
        fflush(fp);
        fclose(fp);
        return env->NewStringUTF(myStr);
    }
    else
    { sprintf("error","errno = %d",errno);
        fclose(fp);
        return env->NewStringUTF("Error opening file!");
    }

   /* std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());*/


}

【问题讨论】:

    标签: android java-native-interface


    【解决方案1】:

    尝试将权限添加到您的清单中:

    <manifest>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        ...
        <application>
            ...
            <activity> 
                ...
            </activity>
        </application>
    </manifest> 
    

    要支持棉花糖,请确保您的活动实现 OnRequestPermissionResult 并添加代码以请求权限(如果尚未授予)(代码取自对此 question 的答案):

    public boolean isStoragePermissionGranted() {
        if (Build.VERSION.SDK_INT >= 23) {
            if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED) {
                Log.v(TAG,"Permission is granted");
                return true;
            } else {
    
                Log.v(TAG,"Permission is revoked");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                return false;
            }
        }
        else { //permission is automatically granted on sdk<23 upon installation
            Log.v(TAG,"Permission is granted");
            return true;
        }
    }
    

    权限结果回调:

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
            Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
            //resume tasks needing this permission
        }
    }
    

    【讨论】:

    • 我已经在清单中添加了这些权限,即使授予了这些权限,文件操作也不会通过。我猜 otg 需要一些其他设备权限
    • 你能分享你得到的异常(比你有更多的细节)吗?
    • 当我在 JNI 中执行 fopen 时,即使文件存在,它也会抛出 null。在进一步检查时,它说权限被拒绝。
    • 如果我尝试使用 USB 主机方法来授予对设备的访问权限,那么它会抛出 open failed: EACCES (Permission denied) 错误
    • 您能否在所有异常(包括 C++ 和 Java)上设置一个断点并给出您得到的确切堆栈和错误?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    • 2019-12-15
    • 2023-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多