I am working on a third-party library for Android and need to be able to tell if I am running as a privileged process with my desired permissions, or if I am living in an isolated process with restricted permissions as defined in the AndroidManifest.xml file:
<service android:name="mySandboxedService" android:permission="com.android.chrome.permission.CHILD_SERVICE" android:exported="false" android:process=":sandboxed_process0" android:isolatedProcess="true" />
The reason being that certain things I'm trying to do, such as get the number of running application processes (and various other things), will throw a RuntimeException if they are isolated. This code will run successfully if not run as an isolated process, but will throw RTE if the process is isolated:
ActivityManager aM = (ActivityManager) context.getSystemService(android.content.Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> l = null;
try {
l = aM.getRunningAppProcesses();
} catch (RuntimeException e) {
Log.w(LOGTAG, "Isolated process not allowed allowed to call getRunningAppProcesses, cannot get number of running apps.");
}
From my logcat:
java.lang.SecurityException: Isolated process not allowed to call getRunningAppProcesses
Does anyone know of a way I can check my current process to see if it is isolated or privileged? I've checked the Android Service doc here, and it does not provide much information.
My end goal is to initialize my app once from the main, privileged thread, and then ignore all of the startup calls from the various sandboxed processes that may get created. I don't want to run in those, but my hook is in Application.onCreate and gets called for every process, sandboxed or not.
I've considered the idea of adding one of these checks to my initialization and catching the RTE if it's thrown. But if there is a public API for it, I'd rather use that.
One can check the uid of the running process to see if they fall in the range of isolated process.
int AID_ISOLATED_START = 99000;
int AID_ISOLATED_END = 99999;
int uid = Process.myUid();
if (uid >= AID_ISOLATED_START && uid <= AID_ISOLATED_END) {
Log.i(TAG, "This is from an isolated process");
}
Process range info source: https://android.googlesource.com/platform/system/sepolicy/+/master/public/isolated_app.te
EDIT: The above has been found to be unreliable on Android 8.1 and below.
Another approach is to try accessing privileged APIs and see if an exception is thrown.
try {
ActivityManager activityManager = (ActivityManager) mContext.getSystemService(ACTIVITY_SERVICE);
activityManager.getRunningAppProcesses();
} catch (SecurityException e) {
Log.i(TAG, "This is from an isolated process");
}
As pointed out in an other answer, Android Pie/9 (API 28) introduced a new API for this. See https://developer.android.com/reference/android/os/Process#isIsolated().
This seems to be present in versions as low as Android 4.3. See https://cs.android.com/android/platform/superproject/+/android-4.3.1_r1:frameworks/base/core/java/android/os/Process.java;l=680
API 28 (Android Pie / 9) introduced new method for checking if current process is an isolated one: Process#isIsolated.
Note that this method was added to Process class in API 16, but was hidden till API 28. Therefore the following method can be used to check if the process is isolated or not (this is actually how Chrome app performs this check):
#SuppressLint("NewApi")
public boolean isIsolated() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
return false;
}
return android.os.Process.isIsolated();
}
Checking if the UID is in the {99000, 99999} range (as demonstrated in the accepted answer) will produce incorrect results in multi-user/profile environment for all users/profiles which are not the main one - since their UIDs will be prefixed with matching user id (example UID for user 10's isolated process will be 1099013).
Related
i am trying to run a process and to read it's data from InputStreamReader, but it fails in a weird way.
The executable is "ip neigh show"
When trying to run the command from connected device via adb shell the command executes OK and also displays data correctly.
But when trying to execute it from kotlin code it exit with exit code 1 and InputStreamReader show empty data also.
This is how i am trying it :
val p = Runtime.getRuntime().exec("ip neigh show")
InputStreamReader(p!!.inputStream).forEachLine fori#{ line ->
val teDhenat = line.split("\\s+".toRegex())
if (teDhenat[0] == ip) {
if (teDhenat.size < 4) {
return#fori
} else {
uGjet = true
macAddress = teDhenat[4]
return#fori
}
}
}
The problem seems to happen in that line : val p = Runtime.getRuntime().exec("ip neigh show") but i don't understand why.
Also tried with val p = Runtime.getRuntime().exec("/system/bin/ip neigh show") and it's still the same.
Also i have tried using ProcessBuilder() and it doesn't work too.
The Compile and Target SDK is 31
The phone is Xiaomi running Android 11 (SDK 30)
PS: Also i am using same logic for other executables and they work very fine like "ping", "top" etc...
Since Android 11 (SDK 30) :
In addition, non-privileged apps can't access the device’s MAC
address; only network interfaces with an IP address are visible. This
impacts the getifaddrs() and NetworkInterface.getHardwareAddress()
methods, as well as sending RTM_GETLINK Netlink messages.
The following is a list of the ways that apps are affected by this
change:
NetworkInterface.getHardwareAddress() returns null for every
interface.
Apps cannot use the bind() function on NETLINK_ROUTE
sockets.
The ip command does not return information about interfaces.
Apps cannot send RTM_GETLINK messages. Note that most developers
should use the higher-level APIs of ConnectivityManager rather than
lower-level APIs like NetworkInterface, getifaddrs(), or Netlink
sockets. For example, an app that needs up-to-date information on the
current routes can get this information by listening for network
changes using ConnectivityManager.registerNetworkCallback() and
calling the network's associated LinkProperties.getRoutes().
I am working with the AndroidX Work Dependency to try and run some background service operations. I am currently running the most recent stable version, 2.2.0 as of posting this question.
The actual operation I am running in the background is a fairly heavy-CPU operation as it is using some compression code in one of my libraries (here) and can take anywhere from 3-30 minutes depending on the size and length of the video in question.
Here is the code I have that builds and runs the work request:
public static void startService(){
//Create the Work Request
String uniqueTag = "Tag_" + new Date().getTime() + "_ChainVids";
OneTimeWorkRequest.Builder builder = new OneTimeWorkRequest.Builder(CompleteVideoBackgroundService.class);
Constraints.Builder constraints = new Constraints.Builder();
constraints.setRequiredNetworkType(NetworkType.CONNECTED);
builder.setConstraints(constraints.build());
builder.setInitialDelay(1, TimeUnit.MILLISECONDS);
builder.addTag(uniqueTag);
Data inputData = new Data.Builder().putString("some_key", mySerializedJSONString).build();
builder.setInputData(inputData);
OneTimeWorkRequest compressRequest = builder.build();
//Set the Work Request to run
WorkManager.getInstance(MyApplication.getContext())
.beginWith(compressRequest)
.enqueue();
}
It then fires off this class which runs all of the background service operations:
public class MyServiceSampleForStackoverflow extends Worker {
private Context context;
private WorkerParameters params;
public MyServiceSampleForStackoverflow(#NonNull Context context, #NonNull WorkerParameters params){
super(context, params);
this.context = context;
this.params = params;
}
/**
* Trimming this code down considerably, but the gist is still here
*/
#NonNull
#Override
public Result doWork() {
try {
//Using using a hard-coded 50% for this SO sample
float percentToBringDownTo = 0.5F;
Uri videoUriToCompress = MyCustomCode.getVideoUriToCompress();
VideoConversionProgressListener listener = (progressPercentage, estimatedNumberOfMillisecondsLeft) -> {
float percentComplete = (100 * progressPercentage);
//Using this value to update the Notification Bar as well as printing in the logcat. Erroneous code removed
};
String newFilePath = MyCustomCode.generateNewFilePath();
//The line below this is the one that takes a while as it is running a long operation
String compressedFilePath = SiliCompressor.with(MyApplication.getContext()).compressVideo(
listener, videoUriToCompress.getPath(), newFilePath, percentToBringDownTo);
//Do stuff here with the compressedFilePath as it is now done
return Result.success();
} catch (Exception e){
e.printStackTrace();
return Result.failure();
}
}
}
Once in a while, without any rhyme or reason to it, the worker randomly stops without me telling it to do so. When that happens, I am seeing this error:
Work [ id=254ae962-114e-4088-86ec-93a3484f948d, tags={ Tag_1571246190190_ChainVids, myapp.packagename.services.MyServiceSampleForStackoverflow } ] was cancelled
java.util.concurrent.CancellationException: Task was cancelled.
at androidx.work.impl.utils.futures.AbstractFuture.cancellationExceptionWithCause(AbstractFuture.java:1184)
at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:514)
at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475)
at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:284)
at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
I am quite literally just staring at my phone with and not interacting with it at all when this randomly happens. I am not trying to run other apps, nor am I trying to hog the CPU for something else. I never see any stacktrace of my own and no immediate problem or cause is visible.
The question therefore is, what is happening here that is randomly stopping the Worker service without any provocation? Why is it randomly stopping operations?
Thanks all.
EDIT 1
I did test removing the network constraints requirement line thinking that may be causing the issue and I did see it occur even after that, so I don't believe that is the problem.
I am testing on a Google Pixel 3, API 28, Android 9, but any other device I have tested regardless of API level (minimum supported is 21) has shown the same issue.
Edit 2
I tried rewriting the class to work on the Asynchronous approach by having the class extend ListenableWorker instead of Worker and that did not resolve the issue.
you are most likely facing one of 2 issues.
First, assuming your background service runs more than 10 minutes can take anywhere from 3-30 minutes depending on the size and length of the video in question, you may be running into a hard time limit which is imposed by the WorkManager code.
In the docs here they say: The system instructed your app to stop your work for some reason. This can happen if you exceed the execution deadline of 10 minutes.
That seems the most likely, but the other issue could be related to Android background limitations outlined here in which it details changes related to Apps that target Android 8.0 or higher. As you mentioned in an edit, you are testing on a Google Pixel 3, API 28, Android 9 and that may be directly related.
As far as solutions go, the simplest, albeit a frustrating solution, would be to tell the user that they need to keep the app in the foreground. This would at least prevent that 10 minute gap.
Another option would be to utilize the new Bubble API that was introduced in API 29. The docs are here and the section of docs that might interest you is where it says, When a bubble is expanded, the content activity goes through the normal process lifecycle, resulting in the application becoming a foreground process. Making a miniaturized 'expanded' view and having that be expanded by users when the app closes my be a good alternative solution to bypassing that 10 minute timer.
We can now run longer than 10 mins, at least according to work manger version Support for long-running workers :
WorkManager 2.3.0-alpha02 adds first-class support for long running
workers. In such cases, WorkManager can provide a signal to the OS
that the process should be kept alive if possible while this work is
executing. These Workers can run longer than 10 minutes. Example
use-cases for this new feature include bulk uploads or downloads (that
cannot be chunked), crunching on an ML model locally, or a task that's
important to the user of the app.
An example is given in the link shared. Please check it out.
I am trying to build a task killer type of app in android. I can show the list of currently running task using ActivityManager but facing problem in killing the task.
Here is what i am doing to get the list of currently running task :
ActivityManager am = (ActivityManager) context.
getSystemService(Activity.ACTIVITY_SERVICE);
List<RunningTaskInfo> a = am.getRunningTasks(Integer.MAX_VALUE);
PackageManager pack = this.getPackageManager();
for(int i = 0; i < a.size(); i++) {
String packageName = a.get(i).topActivity.getPackageName();
Drawable d = null;
String appName = "";
try {
d = pack.getApplicationIcon(packageName);
appName = (String)pack.getApplicationLabel(pack.getApplicationInfo(packageName,PackageManager.GET_META_DATA));
} catch (NameNotFoundException e) {
e.printStackTrace();
}
packName.add(packageName); //arraylist of package name
apps.add(appName); // arraylist of app name
icons.add(d); //arraylist of icons
}
It worked for me But now as I am trying to kill the task using killBackgroundProcesses :
am.killBackgroundProcesses(package name);
It did not work . Also killBackgroundProcesses method is available in API level 2.2 then how can i perform the same task in previous API level such as 1.6 etc.
Is there any other way to show the currently active apps and kill them?
No one can kill process except Android OS itself.
Most of the task killer in android market don't kill the app they just restart the process
by using
public void restartPackage (String packageName)
when this method is called by your activity the operating system immediately called
savedInstanceState and save the state of that activity you want to kill. Now this process is
removed from memory and OS saved it state.Now when next time user start that activity it
will start from where it was killed or in other words restarted. You can verify it from any
task manager that they don't kill the process because no one can do so. This method also
work in ICS.
for above method you can look at here . As far as i know killBackgroundProcesses (String packageName) is for API 8 and above.
In a nutshell, Automatic Task Killers work by polling the OS for a list of currently running processes and the memory they are consuming. Then either with an intelligent algorithm or with user input the Task Killers issue a call to the system telling the system to kill the process. There are two apis you can do this.
They are
Process.sendSignal(pid, Process.SIGNAL_KILL);
ActivityManager.killBackgroundProcesses(PackageName)
This first works by invoking Process.killProcess(int pid) where pid is the unique identifier for a specific process. Android kills processes in the same way that linux does; however, a user may only kill processes that they own. In Android each app is run with a unique UID, user ID. So using this API an App can only kill its own processes, hence the following explanation in the docs for Process.killProcess(int pid):
Kill the process with the given PID. Note that, though this API allows
us to request to kill any process based on its PID, the kernel will
still impose standard restrictions on which PIDs you are actually able
to kill. Typically this means only the process running the caller's
packages/application and any additional processes created by that app;
packages sharing a common UID will also be able to kill each other's
processes.
When this method is called the signals is generated by the OS and set to the process. Whenever a process receives a signal from the OS it must either handle that signal or immediately die. Signals such as SIG_KILL cannot be handled and result in the immediate death of the recipient process. If you want to kill processes that you don't have privileges to kill, i.e. its not your process, then you must escalate your privileges using sudo (this would require root privileges on the device).
The second API works by telling the ActivityManager that you wan to kill processes associated with a specific Package. This API gets around the need for your UID to match the UID of the process because it requires the user to accept the KILL_BACKGROUND_PROCESSES permission. This permission signals to the OS that an app has been approved by the user as a task killer. When a task killer wants to kill an app, it tells the OS to do it getting around the problem of only being able to kill processes that you own.
In the Android Docs it says that this API actually uses the first Process.killProcess API
Have the system immediately kill all background processes associated
with the given package. This is the same as the kernel killing those
processes to reclaim memory; the system will take care of restarting
these processes in the future as needed.
Hope It Helps.
Did you enter below permission in the manifest file?
<uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
I am really struggling with this issue as it seems to occur randomly for me. When I call,
Desktop.browse("some url");
Internet Explorer will not display. The exception message is as follows,
The requested lookup key was not found in any active activation context.
When it occurs it occurs consistently until I restart the machine, but it eventually occurs again.
The workstations that seem to have this problem are running Windows XP with Internet Explorer 8 set as the default browser.
EDIT: I forgot to mention that if I open up Internet Explorer directly and navigate to the URL in question then it will work fine.
EDIT2: This seems to happen if Desktop.browse is invoked and then is called again at least 15 minutes later. Restarting the application now seems to fix the problem.
I narrowed down the problem and discovered what was TRULY causing this, it had nothing to do with the time after all.
java.awt.Desktop.browse("some url"); was throwing this error because in a previous step in the application an ActiveXObject was opened programmatically using the JACOB framework.
The developer that wrote this code using this ActiveXObject neglected to bother releasing his resources at all. For some reason, this ActiveXObject in memory was preventing or screwing with the Dispatch call to the default OS browser in java.awt.Desktop class. I suppose this makes sense.
I fixed this by declaring a JACOB transaction, and by releasing all resources in a finally block like so:
ActiveXObject ao1 = null;
ActiveXObject ao2 = null;
ComThread.initMTA();
try {
ao1 = new ActiveXObject("blaa.blaa");
ao2 = new ActiveXObject("haa.haa");
// business logic
} finally {
if (ao1 != null) {
ao1.safeRelease();
ao1 = null;
}
if (ao2 != null) {
ao2.safeRelease();
ao2 = null;
}
ComThread.Release();
}
I have been developing an app, and I need to close another app in my code. Does anyone know any api to call to close an app?
BTW: my app will be pre-installed.
thanks
Since Android 2.2 (i.e. going forward), you can only close the background processes of other apps, you are no longer able to close their main activities.
If your app is targeting Android <2.2, look atandroid.permission.RESTART_PACKAGE.
If you want it to work properly on 2.2 and above (which you should :-)), look at android.permission.KILL_BACKGROUND_PROCESSES, but again, this only closes background services and such and might "mess up" the other app rather than doing any good.
With the right permissions, you can then do the following:
private ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
am.restartPackage("com.jimmy.appToBeClosed");
Try This
ActivityManager am = (ActivityManager) getApplicationContext().getSystemService("activity");
Method forceStopPackage;
forceStopPackage =am.getClass().getDeclaredMethod("forceStopPackage",String.class);
forceStopPackage.setAccessible(true);
forceStopPackage.invoke(am, pkg);
In manifest file add this
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"></uses-permission>
If both applications are yours, you can use AIDL for inter-process communication to send a message telling the other application to close. See http://developer.android.com/guide/developing/tools/aidl.html.
I have been able to close another app on Android 12 successfully. Here is how:
Basically, I am closing another app from a service although you should be able to do it from an app too.
My service is a privileged system app that gets installed in system/priv-app/ (It has LOCAL_PRIVILEGED_MODULE := true in its Android.mk)
I added <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" /> in AndroidManifest.xml
I added in privapp-permissions.xml
<privapp-permissions package="<my service package name>">
<permission name="android.permission.FORCE_STOP_PACKAGES"/>
</privapp-permissions>
I called in my service this method with the package name of the application I want to close:
private void closePackageApp(String namePackage) {
ActivityManager activityManager = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
try {
Method forceStopPackage = activityManager.getClass().
getDeclaredMethod("forceStopPackage", String.class);
forceStopPackage.setAccessible(true);
forceStopPackage.invoke(activityManager, namePackage);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
I tested this and in the logs, I can see the app is being closed. However the app is not removed from the recent screen (logs suggested the app was disposed without first being removed with the input manager!).
However, I am sure the app was really being closed when it was in the background by comparing its lifecycle on opening again. Normally, it is onPause->onResume but now it is onPause->onCreate.
You don't ever really want to close another application, due to Android activity lifecycle.
There's no benefit, and always detriment to closing another app if it's not yours, and very little benefit to closing your own.
http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
If you know for certain that you'll never, ever need a root activity and its children (an "app"), you can stop it to free memory (it doesn't free that much), but if you do the user may restart it while it's still in cache, stopped, which can cause problems if the stopped state is restored. So this is a bad practice.