I'm a beginner android developer and trying to learn stuff while making a sample app.
my MainActivity's onCreate() execute an AsyncTask that fetches data for my RecyclerView to hold.
the AsyncTask requires Root access and "asks" for it.
my problem is that the MainActivity's layout wont draw until the Root Prompt appears and i click grant\deny.
how can i make the layout draw beforehand?
Thanks in Advance!!!
onCreate():
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
DataFetcher dataFetcher = new DataFetcher();
dataFetcher.execute("");
dataFetcher:
#Override
protected void onPreExecute() {
super.onPreExecute();
if(!canRunRootCommands()) {
Log.e("DataFetcher", "No Root Access");
cancel(true);
}
}
/***********************************************************************/
//Root Check method
//Credit: http://muzikant-android.blogspot.co.il/2011/02/how-to-get-root-access-and-execute.html
/***********************************************************************/
private boolean canRunRootCommands() {
boolean retval = false;
Process suProcess;
try {
suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
DataInputStream osRes = new DataInputStream(suProcess.getInputStream());
if (null != os && null != osRes) {
// Getting the id of the current user to check if this is root
os.writeBytes("id\n");
os.flush();
String currUid = osRes.readLine();
boolean exitSu = false;
if (null == currUid) {
retval = false;
exitSu = false;
Log.d("ROOT", "Can't get root access or denied by user");
} else if (true == currUid.contains("uid=0")) {
retval = true;
exitSu = true;
Log.d("ROOT", "Root access granted");
} else {
retval = false;
exitSu = true;
Log.d("ROOT", "Root access rejected: " + currUid);
}
if (exitSu) {
os.writeBytes("exit\n");
os.flush();
}
}
} catch (Exception e) {
// Can't get root !
// Probably broken pipe exception on trying to write to output stream (os) after su failed, meaning that the device is not rooted
retval = false;
Log.d("ROOT", "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
}
return retval;
}
moved the "canRunRootCommands()" call from onPreExecute to doInBackground to make sure its not running on the UI thread.
Related
I have a variable MyFinalPressure which is populated with sensor data from the sensors pressure. If MyFinalPressure is == to 4000 (4000 points or 40 sec) then stop writing to local storage.
But it looks like when I debug the code, it hits the boolean MaxPoints and is still writing. I wonder if my logic is wrong or not.
Could you please help me out.
public Boolean Store = false;
Boolean MaxPoints = false;
if (activity.Store) {
activity.writeToFile(MyFinalPressure);//MyFinalPressure is float of one dimension array or stream of array.
}
if (MyFinalPressure==4000){ //this conditon, am trying to stop wrting to local memory.
activity.MaxPoints = true;
}
FileOutputStream fileOutputStream;
//method to write into local memory.
public void writeToFile(final float MyFinalPressure) {
Log.d(TAG, "writeToFile.");
String finalData;
finalData = String.valueOf(MyFinalPressure);
try {
// true here for 'append'
fileOutputStream = new FileOutputStream(file, true);
String Space = " ";
byte[] convert = Space.getBytes();
fileOutputStream.write(finalData.getBytes());
fileOutputStream.write(convert);
fileOutputStream.flush();
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//write to file.
StartWriting = (ToggleButton) findViewById(R.id.startWriting);
StartWriting.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (StartWriting.isChecked()) {
Store = true;
Toast.makeText(getApplicationContext(), "Data Starts writing into (Message.txt) file", Toast.LENGTH_LONG).show();
} else {
if (!StartWriting.isChecked()|| MaxPoints==true) { //here - this is wrong logic to stop writing to my file.
Toast.makeText(getApplicationContext(), "Data Stored at myAppFile", Toast.LENGTH_SHORT).show();
String finalData1;
finalData1 = String.valueOf(fileOutputStream);
Log.i(TAG, "of_writes: " + finalData1);
// Toast.makeText(getApplicationContext(), "Data_write_number: " + finalData1.length(), Toast.LENGTH_SHORT).show();
Store = false;
}
}
}
});
Just take out !StartWriting.isChecked()
Because of the above if statement StartWriting.isChecked() will always be false. Then because you are checking for "!StartWriting.isChecked()" it will always enter the statement.
I was been trying to find whether a device is rooted or not and if the device is found rooted i do not want my application to get installed.I have tried two of the below methods
private boolean isRooted() {
return findBinary("su");
}
public static boolean findBinary(String binaryName) {
boolean found = false;
if (!found) {
String[] places = { "/sbin/", "/system/bin/", "/system/xbin/",
"/data/local/xbin/", "/data/local/bin/",
"/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/" };
for (String where : places) {
if (new File(where + binaryName).exists()) {
found = true;
break;
}
}
try {
File file = new File("/system/app/Superuser.apk");
if (file.exists()) {
Log.e("ERROR", "Unable to find icon for package '"
+ "apk found");
found = true;
}
} catch (Exception e1) {
// ignore
}
}
return found;
}
But i don't think that these methods are enough to find a rooted device,since there are tools to hide an apk and the su file can be renamed or deleted.Is there any other way or any suggestions which is 100 percent reliable to find a rooted device?
I was trying to edit the su but couldn't do anything.Is it just a word of mouth or really possible to do so? Thanks in advance
***EDITED***:
I have used "HIDE MY ROOT" application to hide the SU binary aswell as superuser.apk.I can make my rooted device, look like unrooted using hide my root application.Therefore i can say that this source is falseproof and not completely reliable to find rooted device.
Kindly let me know if there is any alternative way to find the rooted device..
I did this in the following way :
/*
* Run su command on device
* #throws IOException, InterruptedException
*/
private static boolean suRun() throws IOException, InterruptedException
{
try {
Process su = null;
su = Runtime.getRuntime().exec(new String[] {"su","-c","exit"});
su.waitFor();
InputStream in = su.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
String suOutput = bufferedReader.readLine();
if (suOutput == null)
{
return true;
}
else
{
return false;
}
} catch (Exception ex)
{
return false;
}
}
public static boolean isPhoneRooted() {
// check if /system/app/Superuser.apk is present and can run su
try {
File file = new File("/system/app/Superuser.apk");
if (file.exists() && suRun()) {
Log.d("Blocking Service", "ROOTED PHONE DETECTED");
return true;
}
}
catch (Throwable e1) {
// ignore
}
return false;
}
you can use SafetyNet API from google play service. this is what being used by android pay not only for the root detection but also to check compatibility with android CTS.
Call isRooted() from ShellInterface
isRooted() depend upon majority of three factor
public static boolean isRooted() {
return isRooted1() ? (isRooted2() || isRooted3()) : (isRooted2() && isRooted3());
}
private static boolean isRooted1() {
Process mProcess = null;
boolean mRoot;
try {
// This is executing on terminal
mProcess = Runtime.getRuntime().exec("su");
mRoot = true;
// If the execute successfully then it return to true
} catch (Exception e) {
// if is not successfully then it return to false
mRoot = false;
} finally {
if (mProcess != null) {
try {
mProcess.destroy();
} catch (Exception ignored) {
}
}
}
return mRoot;
}
private static boolean isRooted2() {
String buildTags = Build.TAGS;
return buildTags !=null && buildTags.contains("test-keys");
}
private static boolean isRooted3() {
boolean mRoot = false;
boolean found = false;
if (!found) {
String[] places = {"/sbin/", "/system/bin/","/system/xbin",
"/data/local/xbin","/system/sd/xbin","/data/local"
};
for (String path : places){
if (new File(path+"su").exists()) {
mRoot = true;
found = true;
}
}
}
return mRoot;
}
I'm building an application that has to take a super user permission to write in the /data directory modify the content of database file. i write some code for getting root access but it is giving me in log Can't "get root access or denied by user"
my code is
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(canRunRootCommands())
Toast.makeText(this, "Can Run Root Commands", Toast.LENGTH_LONG).show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public static boolean canRunRootCommands()
{
boolean retval = false;
Process suProcess;
try
{
suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
DataInputStream osRes = new DataInputStream(suProcess.getInputStream());
if (null != os && null != osRes)
{
// Getting the id of the current user to check if this is root
os.writeBytes("id\n");
os.flush();
String currUid = osRes.readLine();
boolean exitSu = false;
if (null == currUid)
{
retval = false;
exitSu = false;
Log.d("ROOT", "Can't get root access or denied by user");
}
else if (true == currUid.contains("uid=0"))
{
retval = true;
exitSu = true;
Log.d("ROOT", "Root access granted");
}
else
{
retval = false;
exitSu = true;
Log.d("ROOT", "Root access rejected: " + currUid);
}
if (exitSu)
{
os.writeBytes("exit\n");
os.flush();
}
}
}
catch (Exception e)
{
// Can't get root !
// Probably broken pipe exception on trying to write to output stream (os) after su failed, meaning that the device is not rooted
retval = false;
Log.d("ROOT", "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
}
return retval;
}
how to get root access to a so that i can update the database file??
Use the RootTools library, it makes root easier, you don't need to use Process and use a lot of code.
Root is not something you can achieve in normal conditions unless the device is rooted. You cannot FORCE your application to have root outside of non-rooted conditions. Please do research on what root means.
I am looking for a way to detect and access removable sd cards on a variety of Android devices (Samsung, Motorola, LG, Sony, HTC).
I also need to be compatible with 2.2 so Environment.isExternalStorageRemovable() is unavailable for me.
Motorola has its own library, and for Samsung I can detect the existence of /external_sd/
I have no clue for the rest of them. For example, I have seen a /_ExternalSD/ on some LG's but it the directory remains even when the SD is removed.
A bonus question: will the ACTION_MEDIA_MOUNTED intent be broadcast for any of them
Any hint on this would be very helpful.
Here's a class I use to find all sdcards on a device; built in and removable. I've been using it on Ice Cream Sandwich, but it should work at 2x levels.
public class GetRemovableDevice {
private final static String TAG = "GetRemoveableDevice";
public GetRemovableDevice() {
}
public static String[] getDirectories() {
MyLog.d(TAG, "getStorageDirectories");
File tempFile;
String[] directories = null;
String[] splits;
ArrayList<String> arrayList = new ArrayList<String>();
BufferedReader bufferedReader = null;
String lineRead;
try {
arrayList.clear(); // redundant, but what the hey
bufferedReader = new BufferedReader(new FileReader("/proc/mounts"));
while ((lineRead = bufferedReader.readLine()) != null) {
MyLog.d(TAG, "lineRead: " + lineRead);
splits = lineRead.split(" ");
// System external storage
if (splits[1].equals(Environment.getExternalStorageDirectory()
.getPath())) {
arrayList.add(splits[1]);
MyLog.d(TAG, "gesd split 1: " + splits[1]);
continue;
}
// skip if not external storage device
if (!splits[0].contains("/dev/block/")) {
continue;
}
// skip if mtdblock device
if (splits[0].contains("/dev/block/mtdblock")) {
continue;
}
// skip if not in /mnt node
if (!splits[1].contains("/mnt")) {
continue;
}
// skip these names
if (splits[1].contains("/secure")) {
continue;
}
if (splits[1].contains("/mnt/asec")) {
continue;
}
// Eliminate if not a directory or fully accessible
tempFile = new File(splits[1]);
if (!tempFile.exists()) {
continue;
}
if (!tempFile.isDirectory()) {
continue;
}
if (!tempFile.canRead()) {
continue;
}
if (!tempFile.canWrite()) {
continue;
}
// Met all the criteria, assume sdcard
arrayList.add(splits[1]);
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
}
}
}
// Send list back to caller
if (arrayList.size() == 0) {
arrayList.add("sdcard not found");
}
directories = new String[arrayList.size()];
for (int i = 0; i < arrayList.size(); i++) {
directories[i] = arrayList.get(i);
}
return directories;
}
}
The MyLog.d is a trace class that expands Log.d - it can be dropped.
The class reads /proc/mounts/ and:
checks to see if the path name is the internal sdcard directory
checks to see if its a block device
skips mtdblock devices
skips anything that is not mounted
skips secure and asec directories
makes sure it exists, is a directory, and read/write accessible
If all this is matched, it assumes that you have an sdcard and adds the path to the array list. It returns a string array of path names.
To call the getDirectories function, code something similar to:
String[] sdcardDirectories = GetRemoveableDevice.getDirectories();
The paths returned can be used to create a user selection list, scan for a file, or whatever.
Finally, here's two lines of MyLog.d from an emulator test (second line is the emulator sdcard):
09-19 15:57:12.511: D/GetRemoveableDevice(651): lineRead: /dev/block/mtdblock2 /cache yaffs2 rw,nosuid,nodev 0 0
09-19 15:57:12.511: D/GetRemoveableDevice(651): lineRead: /dev/block/vold/179:0 /mnt/sdcard vfat rw,dirsync,nosuid,nodev,noexec,uid=1000,gid=1015,fmask=0702,dmask=0702,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0
Based on Howards class I made some modifications to make it work on the Galaxy S3.
Environment.getExternalStorageDirectory() returns internal storage on the S3.
Removable storage is not necessarily mounted under /mnt
Removable media must have vfat filesystem
_
public static String getDirectory() {
Log.d(TAG, "getStorageDirectories");
File tempFile;
String[] splits;
ArrayList<String> arrayList = new ArrayList<String>();
BufferedReader bufferedReader = null;
String lineRead;
try {
arrayList.clear(); // redundant, but what the hey
bufferedReader = new BufferedReader(new FileReader("/proc/mounts"));
while ((lineRead = bufferedReader.readLine()) != null) {
Log.d(TAG, "lineRead: " + lineRead);
splits = lineRead.split(" ");
// skip if not external storage device
if (!splits[0].contains("/dev/block/")) {
continue;
}
// skip if mtdblock device
if (splits[0].contains("/dev/block/mtdblock")) {
continue;
}
// skip if not in vfat node
if (!splits[2].contains("vfat")) {
continue;
}
// skip these names
if (splits[1].contains("/secure")) {
continue;
}
if (splits[1].contains("/mnt/asec")) {
continue;
}
// Eliminate if not a directory or fully accessible
tempFile = new File(splits[1]);
if (!tempFile.exists()) {
continue;
}
if (!tempFile.isDirectory()) {
continue;
}
if (!tempFile.canRead()) {
continue;
}
if (!tempFile.canWrite()) {
continue;
}
// Met all the criteria, assume sdcard
return splits[1];
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
}
}
}
return null;
}
Based on Howards class I modified the class further on noticing that all of the external removable storage on several phones and tablets that I could find were mounted using vold, the volume mounting daemon.
// skip if not external storage device
if (!splits[0].contains("vold")) {
continue;
}
if (splits[1].contains("/mnt/asec")) {
continue;
}
// Eliminate if not a directory or fully accessible
tempFile = new File(splits[1]);
if (!tempFile.exists()) {
continue;
}
if (!tempFile.isDirectory()) {
continue;
}
if (!tempFile.canRead()) {
continue;
}
if (!tempFile.canWrite()) {
continue;
}
// Met all the criteria, assume sdcard
arrayList.add(splits[1]);
These capabilities are available in all Android versions:
To obtain the application's folder on the external storage, call Context.getExternalFilesDir.
Keep in mind that your app needs explicit permission to access external storage, and that you should check if it is available via Environment.getExternalStorageState
And yes, ACTION_MEDIA_MOUNTED will be broadcast whenever removable media becomes accessible (You should also listen for ACTION_MEDIA_EJECT and ACTION_MEDIA_REMOVED)
This is the method I created and am using. This has worked on Samsung Galaxy S4, Samsung Galaxy Note 3 and Sony Xperia Z2.
private static String[] getRemovableStoragePaths() {
String[] directories;
String[] splits;
ArrayList<String> pathList = new ArrayList<String>();
BufferedReader bufferedReader = null;
String lineRead;
try {
bufferedReader = new BufferedReader(new FileReader("/proc/mounts"));
while ((lineRead = bufferedReader.readLine()) != null) {
Log.d(TAG, "lineRead: " + lineRead);
splits = lineRead.split(" ");
Log.d(TAG, "Testing path: " + splits[1]);
if (!splits[1].contains("/storage")) {
continue;
}
if (splits[1].contains("/emulated")) {
// emulated indicates an internal storage location, so skip it.
continue;
}
// Eliminate if not a directory or fully accessible
Log.d(TAG, "Path found: " + splits[1]);
// Met all the criteria, assume sdcard
pathList.add(splits[1]);
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
}
}
}
// Send list back to caller
if (pathList.size() == 0) {
pathList.add("sdcard not found");
} else {
Log.d(TAG, "Found potential removable storage locations: " + pathList);
}
directories = new String[pathList.size()];
for (int i = 0; i < pathList.size(); i++) {
directories[i] = pathList.get(i);
}
return directories;
}
I want to get the state of the system and then show a dialog (toasts at the moment so the code is short) and allow the user to either mount it rw or ro based on the current state.
I used the following code but it didn't work and I'm confused as to why it's not working.
File system = new File("/system");
if(system.canWrite()){
Toast.makeText(Utilities.this, "System is RW", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(Utilities.this, "System is RO", Toast.LENGTH_SHORT).show();
}
How can this be done?
===============================EDIT===============================
Here is the final code after parsing /proc/mounts for future searchers
private boolean readReadWriteFile() {
File mountFile = new File("/proc/mounts");
StringBuilder procData = new StringBuilder();
if(mountFile.exists()) {
try {
FileInputStream fis = new FileInputStream(mountFile.toString());
DataInputStream dis = new DataInputStream(fis);
BufferedReader br = new BufferedReader(new InputStreamReader(dis));
String data;
while((data = br.readLine()) != null) {
procData.append(data + "\n");
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
if(procData.toString() != null) {
String[] tmp = procData.toString().split("\n");
for(int x = 0; x < tmp.length; x++) {
//Kept simple here on purpose different devices have different blocks
if(tmp[x].contains("/dev/block") && tmp[x].contains("/system")) {
if(tmp[x].contains("rw")) {
Toast.makeText(Activity.this, "System is rw", Toast.LENGTH_LONG).show();
return true;
} else if(tmp[x].contains("ro")) {
Toast.makeText(Activity.this, "System is ro", Toast.LENGTH_LONG).show();
return false;
} else {
return false;
}
}
}
}
}
return false;
}
That's because you query permissions for user. Even if /system is remounted as rw it does not mean your application will get "write" access to it.
As alternative solution, read /proc/mounts file and parse ro/rw status from there.