android listen for app launch - android

I need to develop a service which listen for every activity start.
Must I do something like this?
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfo = am.getRunningAppProcesses();
for (int i = 0; i < runningAppProcessInfo.size(); i++) {
Log.v("Proc: ", runningAppProcessInfo.get(i).processName);
}
And do I need to do it every X seconds? Does it affect battery consumption?

As far as I know there is a class IActivityController.Stub in android.app package.
But this is an {#hide} interface (as someone said there have some method to access #hide api).
We can set a Listener to listen Activity switch like this:
mAm = ActivityManagerNative.getDefault();
try {
mAm.setActivityController(new ActivityController());
} catch (RemoteException e) {
System.err.println("** Failed talking with activity manager!");}
and Class ActivityManagerNative is #hide also.
ActivityController is a class extends IActivityController.Stub .
How to access #hide Api:
you can get the android source code to build an have-#hide-api Android.jar to use.
by reflection.

As far as I know there is currently no way to listen to an app's launch, Unless it is the first time that it is launching.
ACTION_PACKAGE_FIRST_LAUNCH (Broadcast Action: Sent to the installer package of an application when that application is first launched (that is the first time it is moved out of the stopped state).
So I guess your solution is the best for this right now.

Related

How to detect process foreground for Android O

On our application there's a service that is normally started during Application.OnCreate (directly calling context.startService) and also later on via AlarmManager (refactor is in progress to migrate some of its work to JobScheduler).
Our application also have a BroadcastReceiver that gets launched with its direct intent.
Given the new limitations in Android Oreo (https://developer.android.com/about/versions/oreo/android-8.0-changes.html) we're having an issue as follows:
app/process is in background/dead
BroadcastReceiver gets fired by the OS
Application.onCreate() executes before the BroadcastReceiver
Application.onCreate() code tries to run the Service
this leads to crash with "IllegalStateException: Not allowed to start service Intent".
I'm aware of the new recommended ways of launching a Service as answered by CommonsWare here https://stackoverflow.com/a/44505719/906362, but for this specific case, I simply want to have if(process in foreground) { startService }. I'm currently using the following method and it seems to work:
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static boolean isProcessInForeground_V21(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.AppTask> tasks = am.getAppTasks();
return tasks.size() > 0;
}
But I can't find the exact checks Android Oreo is doing (I got as far as here https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/ContextImpl.java on the startServiceCommon method, but from there requireForeground flag seems to go to some native implementation)
So my question:
For the specific purpose of Android Oreo new limitations, how to check if my process is foreground before calling startService?
To continue your investigation: (TL;DR: see between horizontal lines at the bottom)
Disclaimer, I don't know too much about Android, I just like digging in the source code.
Note: you can also navigate the code in Android Studio if you jump to file instead of class:
or searching for text in Project and Libraries.
IActivityManager is defined by AIDL, that's why there are no sources for it:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/app/IActivityManager.aidl#145
Based on how AIDL needs to be implemented I found that ActivityManagerService extends IActivityManager.Stub (God bless Google indexing).
Note I also found this, which might be an interesting read if you're really interested how things work internally.
https://programmer.group/android-9.0-source-app-startup-process.html
ActivityManagerService sources reveal that in Oreo startService is forwarded to ActiveServices which is located in the same package.
Assuming we're looking for an exception like this:
java.lang.IllegalStateException: Not allowed to start service Intent {...}: app is in background uid UidRecord{af72e61 u0a229 CAC bg:+3m52s273ms idle procs:1 seq(0,0,0)}
we have to continue down the rabbit hole: requireForeground gets assigned to fgRequired parameter and the message is here. The condition to allow this depends on the start mode returned by ActivityManagerService.getAppStartModeLocked(packageTargetSdk = 26 or greater, disabledOnly = false, forcedStandby = false).
There are 4 start modes:
APP_START_MODE_NORMAL (needs to be different than this, i.e. !=)
APP_START_MODE_DELAYED (this is ok, i.e. return null)
APP_START_MODE_DELAYED_RIGID
APP_START_MODE_DISABLED
Ephemeral apps will immediately return APP_START_MODE_DISABLED, but assuming this is a normal app, we end up in appServicesRestrictedInBackgroundLocked.
Note: this is where some of the whitelist mentioned in https://stackoverflow.com/a/46445436/253468 is decided.
Since all branches but last return APP_START_MODE_NORMAL, this redirects to appRestrictedInBackgroundLocked where we find our most likely suspect:
int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Apps that target O+ are always subject to background check
if (packageTargetSdk >= Build.VERSION_CODES.O) {
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
So the reason for denial is simply targeting O. I think the final answer to your question of how the OS decides if your app is foreground or background is this condition in getAppStartModeLocked
UidRecord uidRec = mActiveUids.get(uid);
if (uidRec == null || alwaysRestrict || uidRec.idle) {
My guess is that a missing record means it's not running (but then how is it starting a service?!), and idle means it's backgrounded. Notice that in my exception message the UidRecord is saying that it's idle and has been backgrounded for 3m52s.
I peeked into your getAppTasks and it's based on TaskRecord.effectiveUid, so I'm guessing that's quite close to listing UidRecords for your app.
Not sure if this helps, but I'll post it anyway, so if anyone wants to investigate more, they have more info.

How some apps still can get current apps processes and kill them?

Background
In the past, I've found the next method of killing an app's background processes, given its package name:
public static boolean killApp(final Context context, final String packageName) {
final ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
final List<ActivityManager.RunningAppProcessInfo> pids = am.getRunningAppProcesses();
for (int i = 0; i < pids.size(); i++) {
final ActivityManager.RunningAppProcessInfo info = pids.get(i);
if (info.processName.equals(packageName)) {
android.os.Process.killProcess(info.pid);
if (new File("/system/bin/kill").exists()) {
InputStream inputStream = null;
try {
inputStream = Runtime.getRuntime().exec("kill -9 " + info.pid).getInputStream();
final byte[] buffer = new byte[100];
inputStream.read(buffer);
} catch (final IOException e) {
}
StreamsUtil.closeStream(inputStream);
}
am.killBackgroundProcesses(packageName);
return true;
}
}
am.killBackgroundProcesses(packageName);
return false;
}
The problem
Ever since a specific Android version (5.1), the function to get the list of running processes only returns the current app's processes, so it's quite useless to use it.
What I've found
Most apps on the Play Store indeed fail to show a list of processes, and instead, show just the current app's process or a list of services at most.
It seems that some apps still manage to show background apps processes and even be able to kill them. As an example, I've found AVG's app that's capable of doing so, here .
Before they can do it, they tell the user to enable the usage stats settings for the app, which I remember of using for checking general information of apps launch time.
Another app that succeeded killing background processes, yet without any user confirmation , is "fast task killer". It also shows a toast of all processes being killed. I could be wrong, but it seems that it's always the same number of tasks.
I also think there is a relatively easy way to get the list of processes using the "ps" function, but only if the device is rooted (otherwise it will return just the current app's processes).
There was a temporary solution with a library, found here (published here), but this doesn't seem to work on Android 7.1.2 , and most probably on previous versions.
The question
How do apps get the list of apps that have background processes, and how do they kill them?
Is it possible to do so without using the UsageStatsManager class ?

Listener for Phone Events and Voice command

My app uses a microphone(AudioRecord) in a background mode,How to make the listener for phone events and voice commands (like google voice). It is necessary for me to release a microphone(AudioRecord) for use.
I found a solution to phone events: http://www.botskool.com/geeks/how-listen-phone-events-android.
to use: TelephonyManager , PhoneStateListener.
But not to voice commands. Help pls.
There is no specific way you can do this (unfortunately) and it will only be the application that attempts to use the mic resource that will get an error.
What you can do is monitor what the user is doing in the background and react accordingly. Here is the code to check if Google Now has become the foreground application:
public static boolean googleNowForeground(final Context ctx) {
final ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager.getRunningTasks(1).get(0) != null) {
final PackageManager pm = ctx.getPackageManager();
try {
final PackageInfo foregroundAppPackageInfo = pm.getPackageInfo(
activityManager.getRunningTasks(1).get(0).topActivity.getPackageName(), 0);
if (foregroundAppPackageInfo != null) {
if (foregroundAppPackageInfo.packageName.matches(Constants.GOOGLE_NOW_PACKAGE_NAME)) {
return true;
}
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
return false;
}
This is the least 'expensive' way I've found to perform such actions, but the method above is not guaranteed to be called in future OS versions, not to mention having to hard-code the package names you are concerned with....
The 'expense' of monitoring for foreground applications that you know will conflict with your application may be somewhat minimal in comparison to permanently recording audio, but you should code your implementation wisely to minimise the monitor within certain device condition parameters.
I've investigated other methods to monitor intent broadcasts that are associated with mic resources, but they've been less successful than the above.
Requesting that the user create an 'exclude list' for the conflicting applications will allow you to dynamically monitor if they become the foreground application and react accordingly.
Hope that helps....

Detect if an android app is running on background

I want to check if my app is running on a background mode.
The problem is that i have many activities(list activities, map activities etc.). Initially I have tried in the life cycle's resume and pause(or the onUserLeaveHint) methods to set a static boolean as true or false and work with this way. But this obviously can't work because when I move from one activity to another, the previous one get paused.
Also, I've read here on stackoverflow that the getRunningTasks() should be used only for debugging purposes. I did a huge research but I can't find a solution. All I want to do is to be able to detect if a the app is running on a background. Can anyone propose me a way, or express any thought on how can I do that?
You can try the same mechanism (a boolean attribute) but on application side rather than activity side. Create a class which extends Application, declare it in the manifest file under <application android:name=YourClassApp>.
EDIT: I assume you know that activities aren't intended for background processing, if not you should take a look at the Services.
I don't know if this will help but you can use
getApplicaton().registerActivityLifecycleCallbacks(yourClass);
To get a birds eye view of how your activities are displayed in the FG. (For older s/w you can use this)
If your Application has a Service you could have a static get/set which accesses a static variable. Do not do this in Activities though, it causes mem leaks.
But realistically speaking there is no tidy way of tracking if your application is running or not.
I had the same problemen when overwriting the Firebase push messaging default behavior (show notifications only when in the background) I checked how Firebase did this by looking in the .class file com.google.firebase.messaging.zzb:53 (firebase-messaging:19.0.1) which appears to us getRunningAppProcesses. Mind you FireBase is created by Google them self. So I'm assuming it's pretty save to use. Cleaned up version:
List<ActivityManager.RunningAppProcessInfo> runningApps;
boolean isInForeground =false;
if ((runningApps = ((ActivityManager)this.getApplication().getSystemService(Context.ACTIVITY_SERVICE)).getRunningAppProcesses()) != null) {
Iterator runningApp = runningApps.iterator();
int myPid = Process.myPid();
while(runningApp.hasNext()) {
ActivityManager.RunningAppProcessInfo processInfo;
if ((processInfo = (ActivityManager.RunningAppProcessInfo)runningApp.next()).pid == myPid) {
isInForeground = processInfo.importance == 100;
break;
}
}
}

How to detect when the user launches another app? (Android)

I'm trying to build an application where my application runs in the background and detects when the user launches another application so that I can control the flow from thereon.
To illustrate my query, I'd like to specify an example.
My application is running in the background (say as a Service), and the user has just clicked on application 'XYZ'. Is it possible for my app to detect that app 'XYZ' has been launched?
More than just detecting whether 'XYZ's Activity has come to the foreground,I want to detect whther 'XYZ' has been launched or not. Say someone launches 'Whatsapp Messenger', I want to know if my app can know that 'Whatsapp Messenger' has been launched.
EDIT : A lot of people think I'm trying to build malware, but I'm not. I'm trying to build an app for a high school project. I want a stat to see how often I use my camera as part of a psych project. :/
Thanks in advance,
Sumit.
Yes, You can find the which application is launched, by Tracking the Logcat. Just Track on ActivityManager tag with info -I log.
From adb shell Command is,
adb logcat ActivityManager:I *:S
From your application code,
logcat ActivityManager:I *:S
And in Logcat you can find a line something like,
I/ActivityManager( 585): Starting activity: Intent { action=android.intent.action...}
When any application will launched.
It is logcat output that shows that the message relates to priority level "I" and tag "ActivityManager":
Update:
Just add permission in your Application's manifest file,
android.permission.READ_LOGS
I guess you should have a look at "app protector" applications in the Google Play. They detect that user launched another application. That is done by reading system logs. Try opening LogCat and reading logs after you launched any application on device. You'll be surprised.
And where should you go from there? I guess you should try aLogCat app. It's freen and open-source. That will help you to actually read logs.
All this is considered to be a security breach in Android by some developers, though.
I have made a service which can detect if other application launches. I have made it for dialer. similarly that can be replaced by any package name.
#Override
public int onStartCommand(Intent intent, int flags, int startId){
Toast.makeText(this,"Service Started", Toast.LENGTH_LONG).show();
final String str = "";
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
int phonelaunched = 0,phoneclosed =0;
int phonelaunches = 1;
#Override
public void run() {
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfo = am.getRunningAppProcesses();
for ( ActivityManager.RunningAppProcessInfo appProcess: runningAppProcessInfo ) {
Log.d(appProcess.processName.toString(),"is running");
if (appProcess.processName.equals("com.android.dialer")) {
if ( appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND /*isForeground(getApplicationContext(),runningAppProcessInfo.get(i).processName)*/){
if (phonelaunched == 0 ){
phonelaunched = 1;
Log.d(str,"dude phone has been launched");
}
else if (phoneclosed == 1){
phonelaunches++;
phoneclosed = 0;
Log.d(String.valueOf(phonelaunches),"dude that was counter");
}
}
else {
phoneclosed = 1;
Log.d(str,"dude phone has been closed");
}
}
}
}
},2000,3000);
return START_STICKY;
}
Here I go through all the running tasks and check if it is our intended application. If so I check if the application is foreground and application is never launched using 'phonelaunched' variable. phoneclosed is used when intended application is in background and variable is set accordingly.
All this is implemented in Service class
In my book, by the way you posed the question, that sounds like hi-jacking an app in a certain way for your service to control, bordering on malware jinx. But it will not work in Android - plain and simple due to the permissions of each application is different. Thereby, each app are isolated from one another. So to answer your question bluntly, its No.
As the other answer suggested - you can monitor the logcat but.. then again... why?

Categories

Resources