pm command giving Segmentation fault - java

I am trying to update an Apk on Android Remotely. To run the update without the need of user intervention, I am using this post Link .
But the process is returning with the exit code 139 which means Segmentation fault. My tablet is rooted and I have confirmed it.
File file = new File(Constants.UPDATE_APK_PATH);
try {
String[] filenames = file.list();
File apk = new File(file, filenames[0]);
Process pid = Runtime.getRuntime().exec(
new String[] { "su", "-c",
"pm install -r "+apk.getAbsolutePath()});
pid.waitFor();
Can anybody tell what exactly i am doing wrong? The file is present at the location and the signature of both the apk is same.

I'm pretty sure if you use adb install instead of pm install would resolve this issue.
But i believe in this case application does not have enough permissions to install packages.

Related

Running shell commands on Android using Runtime.getRuntime

I am working on a device admin app (has been signed by the manufacturer). I am using it to install other apps using the below adb shell command for android 9 :-
cat /sdcard/Download/myfolder/newapp.apk | pm install -S 1528293
and I am just passing it like this:-
String command = "cat /sdcard/Download/myfolder/newapp.apk | pm install -S 1528293"
Runtime.getRuntime().exec(command);
But I get the error "cat unknown option S ".
The same command works perfectly fine when I run it from adb shell.
Don't know what I am doing wrong and could use some help.
EDIT 1:-
I tried running the command like below:-
String[] commandInstall = {
"/system/bin/sh",
"-c",
"cat /sdcard/Download/myfolder/newapp.apk | pm install -S 1528293"
};
Process process = Runtime.getRuntime().exec(commandInstall);
But now I get the error:-
ava.lang.SecurityException: Reverse mode only supported from shell
at com.android.server.pm.PackageInstallerSession.doWriteInternal(PackageInstallerSession.java:679)
at com.android.server.pm.PackageInstallerSession.write(PackageInstallerSession.java:612)
at android.content.pm.PackageInstaller$Session.write(PackageInstaller.java:852)
at com.android.server.pm.PackageManagerShellCommand.doWriteSplit(PackageManagerShellCommand.java:2447)
at com.android.server.pm.PackageManagerShellCommand.runInstall(PackageManagerShellCommand.java:915)
at com.android.server.pm.PackageManagerShellCommand.onCommand(PackageManagerShellCommand.java:158)
at android.os.ShellCommand.exec(ShellCommand.java:103)
at com.android.server.pm.PackageManagerService.onShellCommand(PackageManagerService.java:21330)
at android.os.Binder.shellCommand(Binder.java:634)
at android.os.Binder.onTransact(Binder.java:532)
at android.content.pm.IPackageManager$Stub.onTransact(IPackageManager.java:2821)
at com.android.server.pm.PackageManagerService.onTransact(PackageManagerService.java:3856)
at android.os.Binder.execTransact(Binder.java:731)
Edit 2:- Prior to android 9, I could just do the below for installing apps:-
Runtime.getRuntime().exec("pm install -r app.apk");
Looking at the source code of PackageInstallerSession I found that it was changed to :-
switch (Binder.getCallingUid()) {
case android.os.Process.SHELL_UID:
case android.os.Process.ROOT_UID:
break;
default:
throw new SecurityException("Reverse mode only supported from shell");
}
Source
So even if it is a system app, the shell command for install might not work. From the commit messages it seems, this was done to let PackageInstaller do this job.
However it seems this again got changed to at some point, but probably is not included in android 9:-
switch (Binder.getCallingUid()) {
case android.os.Process.SHELL_UID:
case android.os.Process.ROOT_UID:
case android.os.Process.SYSTEM_UID:
break;
default:
throw new SecurityException(
"Reverse mode only supported from shell or system");
}
Source
So if the app is a system app , then the best way would be to use PackageInstaller.
from PackageInstallerSession.java:
switch (Binder.getCallingUid()) {
case android.os.Process.SHELL_UID:
case android.os.Process.ROOT_UID:
case android.os.Process.SYSTEM_UID:
break;
default:
throw new SecurityException(
"Reverse mode only supported from shell or system");
}
If your app is under system/app maybe you have to put it in system/priv-app. Hope the origin of the exception helps you somehow.

Changing permissions to read data/anr files programmatically

I want to read the ANR files in the /data/anr/ directory on my device. I have managed to push my apk file to the /system/priv-app/ directory, so I can list the anr files generated by that apk in my program, but I cannot read each file (there are currently 2).
Their current permissions are set to "-rw-------" and when I execute
chmod 644 /data/anr/anr-name using adb shell, the permission changed successfully to "rw-r--r--" and I can read them through my program. However, because it is unpredictable when they generate, I want to change the permission to 644 within my Android Studio java program.
I have tried:
POSIX permissions
Files.setPosixFilePermissions(path, PosixFilePermissions.fromString("rw-r--r--"));
This caused my program to hang at that line.
JNA chmod library using the CLibrary interface
private static CLibrary libc = (CLibrary) Native.loadLibrary("c", CLibrary.class);
libc.chmod("/data/anr/anr-name", 0644);
This caused my program to hang as well.
Runtime.getRuntime().exec()
String[] str = new String[3];
str[0] = "chmod";
str[1] = "644";
str[2] = "/data/anr/anr-name";
Process pro = Runtime.getRuntime().exec(str);
pro.waitFor();
pro.waitFor() returns 1 and pro.getErrorStream() returns "Operation not permitted."
java.io.File.setReadable(boolean readable)
file.setReadable()
file.isReadable() returns false and the file permission has not been changed.
For the record, I have a rooted device. My min AND Target SDK Version are API 26.
I also cannot execute "su" in my program because when I tried, it gave me a "Permission denied" error.
I am completely at loss as to what to do. I just want to read the ANR files from my program.

How to enumerate connected USB storage devices Ubuntu Java

I have an application, mostly in Java' that controls an airborne infrared camera via a webpage GUI (served by the Ubuntu machine) which starts running automatically when the computer is powered up and towards the end of the boot. The application runs as a user, not root, even though the user is not logged in.
After a great many images are collected the data need to be archived by using rsync to a folder on the operator's USB drive. I need to have the USB drive mounted and know its name tag. The computer is headless and the operator, who is on the aircraft, cannot be expected to know Linux in any case.
On an Ubuntu I see that logged in and running the xfce4 GUI, and only then, the drives are listed in /media/user-name/drive-tag (I note that /media/username is owned by root but the folder named for the drive is owned by the user.) and are shown in /etc/mtab :
/dev/sdd1 /media/programmer/DATA-02-2TB vfat rw,nosuid,nodev,uid=1001,gid=1001,shortname=mixed,dmask=0077,utf8=1,showexec,flush,uhelper=udisks2 0 0
How can I, through Java or through a combination of Java and bash, detect and mount a USB storage device?
If that's not possible do I need to ask the user, through the GUI, to enter the device tag or name, e.g., 'DATA-02-2TB' and then create the mount point and mount the USB drive via a script using the information above?
First install usbmount, a Ubuntu tool.
sudo apt-get update
sudo apt-get install usbmount
Then edit the /etc/usbmount/usbmount.conf file:
sudo sed -i 's/MOUNTOPTIONS="/MOUNTOPTIONS="user,umask=000,/' /etc/usbmount/usbmount.conf
These steps are described at Serverfault. Note that only a subset of drive formats is supported including the ubiquitous VFAT.
With this in place USB external drives and thumb drives will mount in /media as /media/usb0 through /media/usb7 and will be listed in /etc/mtab.
/dev/sdc1 /media/usb0 vfat rw,noexec,nosuid,nodev,sync,noatime,nodiratime,umask=000 0 0
I've tested this on my 14.04 machine. Now if I could only get the drive label.
Edit: The sync option does not work well with flash drives. Read the /etc/usbmount/usbmount.conf file for details and remove "sync" from the appropriate line in that file. A full backup made with sync option ran for over an hour before I cancelled it but took only about 5 minutes with sync removed. Note the comment about using pumount to unmount the non-synched drive.
public static ArrayList<String> usbDriveList() throws FileNotFoundException {
final String MTB_ADDRESS = "/etc/mtab";
final String TARGET = "^/media/usb[0-7]$"; // REGEX
final File file = new File(MTB_ADDRESS);
final ArrayList<String> driveList = new ArrayList<String>();
try (Scanner in = new Scanner(file)) {
while (in.hasNext()) {
final String[] splitLine = in.nextLine().split(" ");
if (splitLine[1].matches(TARGET)) {
driveList.add(splitLine[1]); // got it!
}
}
} catch (final FileNotFoundException e) {
throw new FileNotFoundException();
}
return driveList;
}

Call a command in terminal using Java (OSX)

I am trying to write Java code to run wget to retrieve an image from a server
I believe that I have wget properly installed. If I type:
wget http://insitu.fruitfly.org/insitu_image_storage/img_dir_38/insitu38795.jpe
I find the image in my user account folder.
The following Java code was working properly on Ubuntu, but I had to move the project over to OSX (Mountain Lion)
import java.io.*;
import java.io.IOException;
public class runWget
{
public static void main (String args[])
{
String whatToRun = "wget http://insitu.fruitfly.org/insitu_image_storage/img_dir_38/insitu38795.jpe";
try
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(whatToRun);
int exitVal = proc.waitFor();
System.out.println("Process exitValue:" + exitVal);
} catch (Throwable t)
{
t.printStackTrace();
}
}
}
When I try to run it on OSX, I get the runtime error:
java.io.IOException: Cannot run program "wget": error=2, No such file
or directory
I would greatly appreciate if someone could tell me what I am doing wrong.
If wget is indeed installed on your OS X system, then try to specify the full path to it.
Try:
which wget
from the command line, then use that fully qualified path in your Java application.
String whatToRun = "/usr/local/bin/wget http://insitu.fruitfly.org/insitu_image_storage/img_dir_38/insitu38795.jpe";
Pretty obviously, wget is not installed by default in OS X.
Something more interesting is to write functionality like wget your own.
URL url = new URL("http://insitu.fruitfly.org/insitu_image_storage/img_dir_38/insitu38795.jpe");
InputStream in = url.openStream();
OutputStream os = new FileOutputStream(new File("picture.jpe"));
byte byffer[] = new byte[1024];
int nBytesRead;
while ((nBytesRead = in.read(buffer)) != -1)
{
os.write(buffer, 0, nBytesRead);
}
os.flush();
os.close();
in.close();
None of these answers explain what your actual problem is.
The reason Java is failing is that /usr/local/bin isn't on your PATH.
Obviously it is on the path of the bash shell you're running in Terminal. And probably of any new bash shell you start in Terminal (or via ssh, or whatever). That's probably because you've got a line like export PATH=$PATH:/usr/local/bin somewhere in ~/.profile, ~/.bash_profile, ~/.bashrc, or the /etc equivalents.
On linux, all your GUI stuff is a child of a login shell, so putting something in one of those files (as long as you pick the right one) means Java will end up inheriting that PATH no matter how it gets launched. But on Mac, all your GUI stuff is a child of launchd, and any shell you run is just a sibling of your GUI apps, not the parent. So, setting PATH in bash's startup isn't going to affect something launched from the Finder or an IDE or whatever.
Once you understand the problem, you can understand all the different solutions—you can set the default environment launchd gives to user processes, or do the same thing system-wide, or modify /etc/paths, etc.
It looks like wget is not installed on that OSX system. (It isn't on mine either, despite that being a few generations older.) Either install it or find another way to download a picture; Java does have HTTP support built-in natively after all (see the java.net.URL class).
if you get this error one more time , execute command like this :
which wget
Runtime.getRuntime().exec(new String[]{ "/bin/sh" , "-c" ,"/usr/local/bin/wget http://insitu.fruitfly.org/insitu_image_storage/img_dir_38/insitu38795.jpe" })

Where do files in dataDir exist in Android?

I am working on an Android App where a file is given its location like the code given below.
The method is like this:
public boolean log(ApplicationInfo aplinfo)
{
ApplicationInfo objAppinfo;
objAppinfo = apinfo;
_strFilePath = objAppinfo.dataDir;
_strFilePath += "/";
}
Where Appicationinfo is my activity name.
When I see in logcat I am getting file path as
09-07 06:34:41.355: INFO/System.out(525):
FileName::::::::::/data/data/com.andr.activity/Info_SA1.txt
My doubt is where can I find this file, where does this file exist?
When I am trying to read the contents of this file, then the contents that are written in to this file are also visible. But I am not able to find the physical location of the file.
Where does data/data/com.andr.activity path exists?
Can anyone help me in sorting out this issue?
Thanks in Advance.
This lives in the android filesystem, which is different from your computer's file system. To view the files in android filesystem, use adb shell on the command prompt. Run:
adb shell ls /data/data/com.andr.activity. Make sure your device/emulator is connected before you do this.
Or if you are using eclipse, switch to DDMS view and check out the file explorer.
To View file:
adb shell
Inside shell use:
cd /data/data/com.andr.activity
cat filename
Or Use adb pull to copy file to your computer's local filesystem and then view it using any editor. Read more about adb pull here

Categories

Resources