Android 7 jni open() fails + usb camera controls - android

I was using this example with ioctl on android 4.4, 5.1
https://github.com/theicfire/simplewebcam/blob/master/jni/ImageProc.c
I am using this interface to get manual control over parameters like contrast, gain, exposure, white level and etc.
when I tried to move the app to android 7 the fd file fails to open.
fd = open (dev_name, O_RDWR | O_NONBLOCK, 0);
Is there any way to fix this?
I have checked and camera2.api doesn't allow controls over the parameters I need from the camera, and the native code fails because of this error.
edit:
to be more precise, I am using a USB camera connected to the tablet, and android 7 doesn't let met get the device FD even though I am using chmod 666 or 777 to set the permission. is there any way around it or other way to get the controls over exposure, contrast, gain, white lvl?
this is the code I added in the java part, the code fails in the canRead() part
private void InitCameraDevice() throws Exception {
//set permissions to all /dev/video devices before checking them
General.RunAsRoot("chmod 666 /dev/video*");
NativeUtils.setLogName(General.getLogFileName());
File dir = new File("/dev");
File[] videoDevFiles = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith("video");
}
});
boolean cameraFound = false;
for (File deviceFile : videoDevFiles) {
// Process file
if(deviceFile.canRead()) {
cameraFound = (NativeUtils.prepareCamera(deviceFile.getAbsolutePath(), frameWidth, frameHeight) != -1);
if (cameraFound)
break;
}
else
General.logd(STREAM_THREAD_TAG, "Insufficient permissions on [" +
deviceFile.getAbsolutePath() +"].");
}
if(!cameraFound)
throw new Exception("UVC Camera not found!");
}
Thanks for the help

You need to use the Android USB manager APIs to get the FD for your USB device; accessing the /dev node directly bypasses Android's permission enforcement (see the USB guide here) for USB device access.
Applications having access to the /dev node is therefore a security vulnerability that's locked down in more recent Android releases.
Once you have the FD for a USB device from the Java USB API, you can manipulate it in native code if you'd like.

Related

Writing to android wear locally

I'm trying to write a continuous stream of data to android wear locally on the wear device. I've a class called DataSaver that works perfectly fine on the phone side, but the same code would not work on the wear device. I've android permission for write, and read on both wear and mobile.
In the constructor for DataSaver, I've the following:
if (!isExternalStorageWritable()) Log.e(TAG, "External storage is not writable"); //This line does not show anything on the log. So, esExternalStorageWritable returns false.
File rootDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);//Environment.getExternalStorageDirectory();
if (!rootDir.canWrite())
{
Log.d(TAG, "cannot write in the root: "+rootDir.toString()+", space: "+rootDir.getUsableSpace()+", can read: "+rootDir.canRead()+", list: "+rootDir.list());
}
Function isExternalStorageWritable() is implemented as follows:
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable()
{
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state))
{
return true;
}
return false;
}
This always goes inside the if statement where I'm checking if rootDir can write. The rootDir.canRead also returns false. The free space on the device is returned as 2.2GB.
The mkdirs in later lines after that fails because it cannot write to root. Any ideas, suggestions? I would greatly appreciate it.
The problem was I had to manually give permission in settings on the watch for it to work. Basically go to: Settings -> Permissions -> Your app, and check if storage is disabled (it was in my case). Click once to toggle the value.
Remember to have write permission on manifest.

Android : How to enable or disable ADB? [duplicate]

I'm trying to enable ADB (USB debugging) only when my application is running and disabling it when my application is not. I have full access to the phone and it is rooted, su available, etc., but I cannot find a way to do the toggling.
What I've tried so far:
Process proc = Runtime.getRuntime().exec(new String [] { "su", "-c", "setprop", "persist.service.adb.enable", "0"});
proc.waitFor();
Process proc2 = Runtime.getRuntime().exec(new String [] { "su", "-c", "stop", "adbd"});
proc2.waitFor();
This however causes the phone to enter a reboot loop instantaneously.
The code that works is easy:
Settings.Secure.putInt(getContentResolver(),Settings.Secure.ADB_ENABLED, 0); // 0 to disable, 1 to enable
Edit/Update:
Thanks to #MohanT for the following update:
Settings.Global.putInt(getContentResolver(),Settings.Global.ADB_ENABLED, 0); // 0 to disable, 1 to enable
However, the app needs to be a system app to be able to use this. To get out of having to sign it, build a custom rom, etc.. I did the following to get it to be a system app.
First, I installed it regularly using eclipse, then adb shell:
> su
# mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system
# cat /data/app/filename.apk > /system/app/filename.apk
# mount -o remount,ro -t yaffs2 /dev/block/mtdblock3 /system
# reboot
You can achieve by following next steps:
Check whether ADB is currently enabled. To do that you can use a relevant global constant:
Settings.Global.ADB_ENABLED for API 17 and above.
Settings.Secure.ADB_ENABLED prior to API 17.
Use implicit Intent with Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS action to open developers options, where user can enable or disable ADB.
Code example:
Java
public static final int API = Build.VERSION.SDK_INT;
public static final int ENABLED=1, DISABLED=0;
public static boolean adbEnabled(Context context){
if(API>16)
return ENABLED == Settings.Global.getInt(context.getContentResolver(), Settings.Global.ADB_ENABLED,DISABLED);
else
return ENABLED == Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.ADB_ENABLED,DISABLED);
}
public void checkAdb(Context context){
//if ADB disabled
if(!adbEnabled(context)){
//open developer options settings
Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
context.startActivity(intent);
}
}
Kotlin
val API = Build.VERSION.SDK_INT
val ENABLED = 1
val DISABLED = 0
fun adbEnabled(context: Context): Boolean {
return if (API > 16)
ENABLED == Settings.Global.getInt(context.contentResolver, Settings.Global.ADB_ENABLED, DISABLED)
else
ENABLED == Settings.Secure.getInt(context.contentResolver, Settings.Secure.ADB_ENABLED, DISABLED)
}
fun checkAdb(context: Context) {
//if ADB disabled
if (!adbEnabled(context)) {
//open developer options settings
val intent = Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)
context.startActivity(intent)
}
}
Just for reference:
Prior to API 3 (probably no longer relevant) Settings.System.ADB_ENABLED was used.
Chris's answer is correct except the ADB_ENABLED field in Secure class has been depreciated and the string has been moved to Global class. So you can use below command -
Settings.Global.putInt(getContentResolver(),Settings.Global.ADB_ENABLED, 0); // 0 to disable, 1 to enable
From my experiences using setprop doesn't always work reliable, and might even conflict with the Settings > Applications > Development > USB Debugging option. Besides that it might be irritating for instance if USB debugging is enabled but adb doesn't work etc. Therefore using Settings.Secure.ADB_ENABLED is the prefered way... plus you always have the notification in the status panel.
If you don't want to go through the hassle to install your app on system partition when only trying to access Settings.Secure.ADB_ENABLED then you can instead rely on another app that is doing this work already:
This app is called ADB Toggle. You can find it in Google Play:
https://play.google.com/store/apps/details?id=com.ramdroid.adbtoggle
The library to access USB debug settings via ADB Toggle is available here:
https://github.com/ramdroid/AdbToggleAccessLib

Unauthorized Caller Error

I am stuck writing some code that uses reflection that calls IConnectivityManager.startLegacyVpn
The error I get is java.lang.SecurityException: Unauthorized Caller
Looking through the android source I see this is the code hanging me up:
if (Binder.getCallingUid() != Process.SYSTEM_UID) { raise the above exception }
My question is if I root my AVD and install my app in system/app will this be sufficient to get around this error?
If so, any tips on how to do this (every time I try to move my apk to the system/app folder it says the app is not installed when I click on the app icon.
Thanks!
I have the same problem, following android 4.01 open source, i see somethings like this:
public synchronized LegacyVpnInfo getLegacyVpnInfo() {
// Only system user can call this method.
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Unauthorized Caller");
}
return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo();
}
Or,
// Only system user can revoke a package.
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Unauthorized Caller");
}
Or,
public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
PackageManager pm = mContext.getPackageManager();
ApplicationInfo app = pm.getApplicationInfo(mPackage, 0);
if (Binder.getCallingUid() != app.uid) {
throw new SecurityException("Unauthorized Caller");
}
jniProtect(socket.getFd(), interfaze);
}
However, these block of code above is belongs to com.android.server.connectivity.Vpn
(class Vpn), which is not defined in interface IConnectivityManager.
I also find in startLegacyVpnInfo() function but i can't see anything involve exception
"Unauthorized Caller", so i wonder why startLegacyVpnInfo() function throws this exception?
Any solutions for this?
I am trying to make the same calls. So far I can confirm that rooting the device and copying the apk to /system/app does not work, it does not start under the system uid.
Also, this does not work:
Field uidField = Process.class.getDeclaredField("SYSTEM_UID");
uidField.setAccessible(true);
uidField.set(null, Process.myUid());
Those calls succeed, but they don't seem to affect the SYSTEM_UID field, the field is probably optimized out at compile time.
If you include android: sharedUserId="android.uid.system" into your manifest tag (not just the manifest), this should then run the application as system. This should now let you run the code.
As for pushing to /system/app, you need to run adb root followed by adb remount. This will now let you push to /system/app.

Looking to enable and disable (toggle) ADB or USB debugging using command line or in app

I'm trying to enable ADB (USB debugging) only when my application is running and disabling it when my application is not. I have full access to the phone and it is rooted, su available, etc., but I cannot find a way to do the toggling.
What I've tried so far:
Process proc = Runtime.getRuntime().exec(new String [] { "su", "-c", "setprop", "persist.service.adb.enable", "0"});
proc.waitFor();
Process proc2 = Runtime.getRuntime().exec(new String [] { "su", "-c", "stop", "adbd"});
proc2.waitFor();
This however causes the phone to enter a reboot loop instantaneously.
The code that works is easy:
Settings.Secure.putInt(getContentResolver(),Settings.Secure.ADB_ENABLED, 0); // 0 to disable, 1 to enable
Edit/Update:
Thanks to #MohanT for the following update:
Settings.Global.putInt(getContentResolver(),Settings.Global.ADB_ENABLED, 0); // 0 to disable, 1 to enable
However, the app needs to be a system app to be able to use this. To get out of having to sign it, build a custom rom, etc.. I did the following to get it to be a system app.
First, I installed it regularly using eclipse, then adb shell:
> su
# mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system
# cat /data/app/filename.apk > /system/app/filename.apk
# mount -o remount,ro -t yaffs2 /dev/block/mtdblock3 /system
# reboot
You can achieve by following next steps:
Check whether ADB is currently enabled. To do that you can use a relevant global constant:
Settings.Global.ADB_ENABLED for API 17 and above.
Settings.Secure.ADB_ENABLED prior to API 17.
Use implicit Intent with Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS action to open developers options, where user can enable or disable ADB.
Code example:
Java
public static final int API = Build.VERSION.SDK_INT;
public static final int ENABLED=1, DISABLED=0;
public static boolean adbEnabled(Context context){
if(API>16)
return ENABLED == Settings.Global.getInt(context.getContentResolver(), Settings.Global.ADB_ENABLED,DISABLED);
else
return ENABLED == Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.ADB_ENABLED,DISABLED);
}
public void checkAdb(Context context){
//if ADB disabled
if(!adbEnabled(context)){
//open developer options settings
Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
context.startActivity(intent);
}
}
Kotlin
val API = Build.VERSION.SDK_INT
val ENABLED = 1
val DISABLED = 0
fun adbEnabled(context: Context): Boolean {
return if (API > 16)
ENABLED == Settings.Global.getInt(context.contentResolver, Settings.Global.ADB_ENABLED, DISABLED)
else
ENABLED == Settings.Secure.getInt(context.contentResolver, Settings.Secure.ADB_ENABLED, DISABLED)
}
fun checkAdb(context: Context) {
//if ADB disabled
if (!adbEnabled(context)) {
//open developer options settings
val intent = Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)
context.startActivity(intent)
}
}
Just for reference:
Prior to API 3 (probably no longer relevant) Settings.System.ADB_ENABLED was used.
Chris's answer is correct except the ADB_ENABLED field in Secure class has been depreciated and the string has been moved to Global class. So you can use below command -
Settings.Global.putInt(getContentResolver(),Settings.Global.ADB_ENABLED, 0); // 0 to disable, 1 to enable
From my experiences using setprop doesn't always work reliable, and might even conflict with the Settings > Applications > Development > USB Debugging option. Besides that it might be irritating for instance if USB debugging is enabled but adb doesn't work etc. Therefore using Settings.Secure.ADB_ENABLED is the prefered way... plus you always have the notification in the status panel.
If you don't want to go through the hassle to install your app on system partition when only trying to access Settings.Secure.ADB_ENABLED then you can instead rely on another app that is doing this work already:
This app is called ADB Toggle. You can find it in Google Play:
https://play.google.com/store/apps/details?id=com.ramdroid.adbtoggle
The library to access USB debug settings via ADB Toggle is available here:
https://github.com/ramdroid/AdbToggleAccessLib

Android: Unable to open device file in JNI implementaion

I have taken Code Aurora's FM Radio code and merged with my Android Gingerbread codebase.
The FM app framework tries to access the fm radio device ( /dev/radio ) using JNI which is implemented in a file by name android_hardware_fm.cpp . There is a function in this file which tries to acquire a file descriptor to the device node using open() in the read/write mode. However, the call fails with error code -13 : Permission denied.
I also made a small C executable which tries to open the /dev/radio file ( in RDWR mode), prints its fd and closes it. It runs from /system/bin in the target system and displays a valid fd.
Btw, the JNI implementation is part of the android core library. It is located in frameworks/base/core/jni and is compiled as part of libandroid_runtime.so
Any ideas/solutions? Thanks in advance.
Clearly you donot have permissions to open the device from user space. In the second case when you are running the executable from terminal, you are having permissions probably because you have done su before running the executable.
For your problem here, two things can be done.
1) Change the permissions of the node from terimnal.
Steps involved:
Open the terminal (adb shell)
Do su(In order to do this your device must be rooted)
Do chmod 777 /dev/radio in the terminal
Once this is done, your radio node is having proper permissions for the user to read and write. So you can now do open() call and it will work.
2) Programmatically you can achieve this (assuming your device is rooted and su is running on your device) by calling the below function - changePerm(). This is a small function I have written which will change the permissions of the device nodes or rather any system file that does not have user access. Once you have permissions, you can open it from user space. open() call will work properly after this.
void changePerm()
{
Process chperm;
try {
chperm=Runtime.getRuntime().exec("su");
DataOutputStream os =
new DataOutputStream(chperm.getOutputStream());
os.writeBytes("chmod 777 /dev/radio\n");
os.flush();
os.writeBytes("exit\n");
os.flush();
chperm.waitFor();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I have tested this for other nodes. So it should also work for radio aswell. Let me know in case yo are facing any difficulty. Thanks

Categories

Resources