Android permissions for a testcase - android

I'm working on a testcase for my application that should verify the correctness of an file import action. To automatically test this, my plan is to copy a file from my test assets directory into the downloads folder of the device under test and perform the import action using an Espresso test case.
Does somebody have experience with this? I'm running into the issue that my test case has no permission to write anything to the device.
So far I have created a dedicated manifest.xml file for my test application containing the required permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Furthermore, I'm performing this action before my test starts to grant the needed permission to the test case:
adb shell pm grant com.my_app_pacakge.test android.permission.WRITE_EXTERNAL_STORAGE
Unfortunately, when I create the file in the downloads directory the following exception is thrown at the moment I try to write contents to the backup file:
Caused by: java.io.FileNotFoundException: /storage/emulated/0/Download/small_backup: open failed: EACCES (Permission denied)
The relevant code is the following:
public void putBackupFile(String name ){
File backupFile = new File(Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS ).getPath(), name );
try {
InputStream is = InstrumentationRegistry.getInstrumentation().getContext().getAssets().open( name );
FileOutputStream fileOutputStream = new FileOutputStream(backupFile);
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, len);
}
fileOutputStream.close();
is.close();
} catch (IOException e1) {
throw new RuntimeException(e1);
}
}
The exception is triggered at: FileOutputStream fileOutputStream = new FileOutputStream(backupFile);

Answering to the original question: If you grant android.permission.WRITE_EXTERNAL_STORAGE from adb, you have to grant android.permission.READ_EXTERNAL_STORAGE as well:
adb shell pm grant com.my_app_pacakge.test android.permission.READ_EXTERNAL_STORAGE
It seems to be that if one ask for WRITE permission in an app, the READ permission is asked/granted automatically. If one does it from adb, the READ permission have to be granted additionally.

I realized that the appraoch states in my question was not the best approach: I have solved this in another way: transferring the required files using the adb command line:
adb push small_backup /mnt/sdcard/Download
This statement is integrated in my test setup (executed before running the test). In the test case I take for granted that the required files are available.

Related

Getting a Permission denied error when creating a file with Android, even when permission is given

I have this in my manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
This is where I am trying to create and write to a file (it is in a file called EnterUserInfo.java:
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
/**
* Checks if the app has permission to write to device storage
*
* If the app does not has permission then the user will be prompted to grant permissions
*
* #param activity
*/
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
System.out.println("INSIDEEEEEE");
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
} else {
System.out.println("HEREEEEEEEEE");
}
}
private void writeToFile(String data, Context context) {
verifyStoragePermissions(this);
String FILENAME = "new_clients.txt";
String string = "hello world!";
try {
FileOutputStream fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
FileOutputStream fos = context.openFileOutput("new_clients.txt", Context.MODE_PRIVATE);
fos.write(data.getBytes());
fos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
When I try to create a file, this is what appears:
I/System.out: HEREEEEEEEEE
W/ContextImpl: Failed to ensure /data/user/0/c.b.project/files: mkdir failed: EACCES (Permission denied)
W/FileUtils: Failed to chmod(/data/user/0/cs.b07.cscb07courseproject/files): android.system.ErrnoException: chmod failed: EACCES (Permission denied)
W/System.err: java.io.FileNotFoundException: /data/user/0/c.b.project/files/new_clients.txt (Permission denied)
W/System.err: at java.io.FileOutputStream.open(Native Method)
W/System.err: at java.io.FileOutputStream.<init>(FileOutputStream.java:221)
W/System.err: at android.app.ContextImpl.openFileOutput(ContextImpl.java:506)
W/System.err: at android.content.ContextWrapper.openFileOutput(ContextWrapper.java:192)
W/System.err: at EnterUserInfo.writeToFile(EnterUserInfo.java:69)
As you can see, it prints here meaning the permission is granted, but right after it gives a Permission Denied error. Any idea how to solve this?
Edit: On a side note, when it says that it tries to save to /data/user/0/cs.b07.cscb07courseproject/files, is that within the project or is that saved on my computer? Because when I go to my terminal and do cd /data/ or cd /data neither is found.
Edit: writeToFile() is called in the same class and file posted above, and this is the code (the function below is called when a user hits the "register" button in the UI:
public void createNewUser(View view) {
// a data string is created here:
// String data = "asd";
writeToFile(data, this);
}
Edit 2: Please note that I did ask for permission at runtime in my verifyStoragePermissions() method. Unless something is wrong with that way of asking for permission (which I don't think it is because a prompt does appear which asks the user for permission), then I think the issue is with something else.
You do not need any permissions to call openFileOutput(). This writes a file to the private application-specific data area, which is owned by your application.
Judging by these errors:
W/ContextImpl: Failed to ensure /data/user/0/c.b.project/files: mkdir failed: EACCES (Permission denied)
W/FileUtils: Failed to chmod(/data/user/0/cs.b07.cscb07courseproject/files): android.system.ErrnoException: chmod failed: EACCES (Permission denied)
It looks like someone has changed the file ownership (or access rights) on your application's private data directory /data/user/0/c.b.project/. This directory should be owned by your application's user ID and therefore your application should have the necessary rights to write to it.
Uninstall your app (which should delete that directory) and then reinstall your app (which should recreate the directory with the correct permissions).
Requesting Permissions at Run Time
Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. This approach streamlines the app install process, since the user does not need to grant permissions when they install or update the app.
More about runtime permission
Refer Answer
Hi firstly you have to check which android SDK version you are using
if it is less than 23 than you just have to put your permission in manifest file it work
if android version greater than 23 you should put all permission in manifest file as well as you should ask user permission for run time ( only first attempt )
for this you should follow this link https://stackoverflow.com/a/33162451/4741746
One more thing you can don is to change compileSdkVersion and buildToolsVersion to below 23 like 22 (but i will not suggest you for this because new features above 23 you can not be use )
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 23
}
}
if not working let me know

saving file on sdcard with permission error

After countless searching I've managed to find path to my sdcard not the android emulated storage. But when I try to make .txt folder there it ends up with error
/storage/37F0-1515/DCIM/100MEDIA/test.txt: open failed: EACCES (Permission denied)
I don't know why because I have permissions for
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
and also I've enabled the permissions with
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, request2);
}
Here is the code that I'm using
File sdCard = new File("/storage/37F0-1515/DCIM/100MEDIA");
File dir = new File(sdCard.getAbsolutePath());
if (!dir.exists()) {
dir.mkdirs();
}
final File file = new File(dir, "test" + ".txt");
try {
BufferedWriter bufferedWriter = null;
bufferedWriter = new BufferedWriter(new FileWriter(file));
bufferedWriter.write("test");
bufferedWriter.close();
}
catch(Exception e){Log.v("myApp", e.toString());}
I don't know why android won't let me write to sdcard. Do I need some other permissions ?
I don't know why because I have permissions for
Those permissions are for external storage, not removable storage.
I don't know why android won't let me write to sdcard
You do not have arbitrary filesystem access to removable storage on Android 4.4+.
Try using these methods-
Check if the uses-permission statements are in the right place, they should be below <manifest> and above <application> tags. The correct format -
<manifest>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
...
<application>
...
<activity>
...
</activity>
</application>
</manifest>
Starting from Android Kitkat, there is a new storage policy -
The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external storage on a device. Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions. Restricting writes in this way ensures the system can clean up files when applications are uninstalled.
This can however be exploited without rooting(although I have not tried this one), as mentioned here
EDIT -
The above mentioned exploit won't work for Android 5+. There is no standard solution to this problem. Some exploits may be available but they will be device-specific/not reliable/root-access dependent.
However, tools like the Storage Access Framework can be used.

Android : Create a file in /data/local/tmp from an automated test

Goal:
Taking a screenshot during an automated test on a device. Pull the screenshot file using adb once the test is done.
Context:
I'm currently trying to write automated tests to take snapshots of the device screen. Using UiDevice to navigate, I would like to take a screenshot in the middle of a test. UiDevice has a method takeScreenshot that I call when I would like to take a snapshot.
After some investigation, I realised that the class responsible to write the image into file UiAutomatorBridge catches an Exception :
java.io.FileNotFoundException:
/data/local/tmp/screenshots/screen2.png: open failed: EACCES
(Permission denied)
Using adb, I created the file and set all permissions to all users.
adb shell touch /data/local/tmp/screenshots/screen1.png
adb shell chmod 777 /data/local/tmp/screenshots
Once done, I can take a screenshot with :
#Test
public void takeSnapShot() {
String filename = "/data/local/tmp/screenshots/screen1.png";
File file = new File(filename);
assertEquals(true, mDevice.takeScreenshot(file));
}
Problem :
I would like to be able to create a file directly while the test is executing, without the need of using adb.
I tried to create a file directly from Java using createNewFile.
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
But I get an IOException
java.io.IOException: open failed: EACCES (Permission denied)
Has anyone an idea of what is going on ? I'm quite new to Linux, so don't hesitate to suggest something even if it seems obvious to you ;)
Should I post this on superuser instead ?
EDIT
The directory /data has these permissions
drwxrwx--x system system 2016-01-14 14:03 data
I can't list the content of /data, which makes me believe the user "shell" doesn't belong to the group "system". I can't list the content of /data/local neither.
However, the /data/local/tmp is owned by "shell".
drwxrwx--x shell shell 2016-01-14 12:20 . (tmp)
/data/local/tmp gives +x permission to all users.
Finally, the directory "screenshots" belongs to shell with permissions 777.
drwxrwxrwx shell shell 2016-01-14 11:46 screenshots
To my understanding, any user should be able to access /data/local/tmp/screenshots
Instead of saving under /data/local/tmp/, use Environment.getExternalStorageDirectory().
You need a read/write permission to do that. You have to add these two lines into the Manifest of the application ! (I tried to add those lines into the /androidTest/Manifest.xml file, but it has no effects).
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
While it solves the problem of finding a common directory to save/read screenshots, it brings a new one as well.
Having to add these 2 permissions isn't a big deal if you already had them. But if you don't want to ask the user for those permissions, you have to add/remove these lines every time you test/sign your application, which is far from ideal.
EDIT :
In this post, someone proposed to make use of the build differentials (debug, release) to have two different Manifests.
In the end, I have 3 Manifests :
Release Manifest (without external read/write permissions)
Debug Manifest (with external read/write permissions)
AndroidTest Manifest for
tools:overrideLibrary="android.support.test.uiautomator.v18"

How do I grant super user permission to fileinputstream object and read all system files on my rooted device

I have a rooted device I am trying to read files from a specific folder /sdcard/videos using FileInputStream and successfully created a CHECKSUM value for that folder, Now I want to read all the files from my system folder and create a checksum value for it but when I pass the folder path which is /system I am unable to read few files and get the following error:
java.io.FileNotFoundException: system/bin/run-as: open failed: EACCES (Permission denied)
How do I overcome this, how do I grant super user permission or root access to read all the system related files ?
Simplified: Programatically Read file from sdcard/system folder using fileinputstream on rooted device
Havent tried it yet
Process p = Runtime.getRuntime().exec(new String[]{"su", "-c", "system/bin/sh"});
DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
//from here all commands are executed with su permissions
stdin.writeBytes("md5sum filepath");
/* executes the md5sum binary command,replace with installation path of md5sum after you install busybox */
InputStream stdout = p.getInputStream();
byte[] buffer = new byte[BUFF_LEN];
int read;
String out = new String();
//read method will wait forever if there is nothing in the stream
//so we need to read it in another way than while((read=stdout.read(buffer))>0)
while(true){
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<BUFF_LEN){
//we have read everything
break;
}
}
Create checksum by calling the md5sum binary
ie. If you have BusyBox installed on your device

Install .APK from Android Cache

I have problems installing an APK saved in Android internal Cache.
There are no issues saving the file in External Storage or on External Cache using context.getExternalCacheDir().
But if I try to use context.getCacheDir(), the log returns
/data/data/com.my.package/cache/update.apk: open failed: EACCES (Permission denied)
File file = context.getCacheDir();
File outputFile = new File(file, "update.apk");
if(outputFile.exists()){
outputFile.delete();
}
FileOutputStream fos = new FileOutputStream(outputFile);
InputStream is = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
}
fos.close();
is.close();
Intent intent = new Intent(Intent.ACTION_VIEW);
//SAVE IN CACHE
intent.setDataAndType(Uri.fromFile(outputFile), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // without this flag android returned a intent error!
context.startActivity(intent);
It looks like internal cache doesn't allow the APK to be correctly read.
The fact is, if the file is saved on the External Storage or external Cache the APK will be available to the user, and I don't want that.
What can it be don to save the file in internal Cache?
Thanks
It looks like internal cache doesn't allow the APK to be correctly read.
That is because the installer app has no rights to read your file.
The fact is, if the file is saved on the External Storage or external Cache the APK will be available to the user, and I don't want that.
Then do not install it on the user's device. Any user can copy any APK off their device at any time after installation, so the only way to prevent the user from accessing the APK is to not have it on the device in the first place.
What can it be don to save the file in internal Cache?
Probably nothing. If you switch to openFileOutput(), you can see if MODE_WORLD_READABLE will be sufficient for the installer to proceed. Again, this will not stop the user from being able to access the APK file.
Try to look chmod command to get read\write permissions on internal folder... As for linux it looks like...
chmod 777 /data/data/*** or chmod 644 /data/data/***

Categories

Resources