There is an application and it needs system reboot after installation. I registrered boot receiver and write info to system log. And activity checks for this line. It works well, but there is one problem...
When user uninstall and install this app in one session(I mean user doesn't reboot phone) system log still has line "Phone restarted" and application runs with errors.
As I know I can't check uninstallation event on my app cause receiver stops before the application going to uninstall. So my question is could I check for my app installation? or maybe uninstallation any other way?
Thanks!
Maybe someone will be interested. I found the code that allows me to checked system reboot after installation/update:
public static boolean phone_rebooted(Context ctx) {
ApplicationInfo appInfo = ctx.getApplicationInfo();
String appFile = appInfo.sourceDir;
long installed = new File(appFile).lastModified();
long boot_time = System.currentTimeMillis() - SystemClock.elapsedRealtime();
if(boot_time < installed) {
return false;
} else {
return true;
}
}
Related
I need to check if a clone of my app is installed on an Android device.
It is a big security concern for my ongoing project.
Update:
I've now realised that clones are not installed but are actually able to run as a seperate instance without disturbing the original one.
Example of an app cloner:
https://play.google.com/store/apps/details?id=com.lbe.parallel.intl
How am I supposed to check at runtime that the running app has only one instance?
Android utilizes unique package strings to identify applications. Your application has a unique package string associated with it just like all Android apps.
To check if an app is installed on the device, you use the Package Manager and check with this code:
public static boolean doesUserHaveFacebookAppInstalled(Context context,
String packageString){
try{
context.getPackageManager().getApplicationInfo(packageString, 0 );
return true;
} catch( PackageManager.NameNotFoundException e ){
return false;
}
}
So if you wanted to check if, for example, Facebook is installed, you would pass in their package string of com.facebook.katana. If it returns true, it is installed, if it is false, it is not installed.
In your situation, only one package is allowed on a device at a time, but the package String can be altered when creating a build. IE, your app package String could be com.myapp.somename and a debug version could be com.myapp.somename-debug. Both would be allowed to be installed as they are unique package Strings.
If you want to check what apps are installed on the device, you can use this code and it will get all installed applications that can be launched / opened:
public static List<ResolveInfo> getAllInstalledApps(Context context){
try {
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> pkgAppsList = context.getPackageManager()
.queryIntentActivities( mainIntent, 0);
for(ResolveInfo r : pkgAppsList){
if(r != null) {
//You can use this String here to identify it while looping.
String packageString = r.toString();
}
}
return pkgAppsList;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Use the results of the second code snippet to identify what apps are installed and check against the package string variations for your app to determine if other ones are installed.
There is no generic solution for this problem; some dual apps hook the system API, some run the app with different userId, and some clone the apk to a single mini VM to run.
The best approach, in my opinion, is to make your app can log-in at one place only when you open the app, connect to your server and your server forces to offline the previously logged-in device.
In that case, you may need a long connection or publish-subscribe-based messaging framework in your project (e.g., MQTT)
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 ?
My android application will be preinstalled. And I want to keep tracking of preinstalled apps.
For this purpose I need somehow to save a key or a flag (which means that app is preinstalled). I will add this key to each request to my back-end and will analyze it.
I have an issue with that. An issue is about update from Google Play.
The standart workflow is the following:
1) I give to a manufacturer a special version of my application, which saves a key somehow (in Shared Prefs for example).
2) Manufacturer sell device with the app (special, modified).
3) When User get it, there definetly be next version of the app (standart, without special code) in the Google Play, so user perhaps update it without any launching (the worst case).
4) I lost my tracking possibility. (new apk fully removing never launched old one which was special)
To solve it I was listening a system broadcast ON_BOOT_COMPLETE, but its not working properly on Android 3.1+.
Have you any ideas how can I do that?
Can you install an additional .apk that only has a service? Then that service can have the key, etc. and it can listen for when your app starts and send the tracking info. Then it won't matter if your app gets upgraded; the service will still be the same.
There are some ways to know if application is system application or not. Like by checking installed directory of application or check FLAG_SYSTEM for the application.
Method 1 : -
Check location of application
public static boolean applicationIsSystemApp(Context mContext, String packageName) {
try {
ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);
String appLocation = applicationInfo.publicSourceDir;
// OR String appLocation = applicationInfo.sourceDir;
// Both returns the same
// if package is pre-installed then output will be /system/app/application_name.apk
// if package is installed by user then output will be /data/app/application_name.apk
// Check if package is system app
if (appLocation != null && appLocation.startsWith("/system/app/")) {
return true;
}
} catch (NameNotFoundException e) {
e.printStackTrace(); // TODO Can handle as your logic
}
return false;
}
Method 2 : -
Check FLAG_SYSTEM of application
public static boolean applicationIsSystemApp(Context mContext, String packageName) {
try {
ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);
// FLAG_SYSTEM is only set to system applications,
// this will work even if application is installed in external storage
// Check if package is system app
if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
}
} catch (NameNotFoundException e) {
e.printStackTrace(); // TODO Can handle as your logic
}
return false;
}
And call this method as
if (applicationIsSystemApp(getApplicationContext(), "com.example.mysystemapp")) {
// Application is system app
} else {
// Application has been installed as 3rd Party app
}
There is a property sourceDir in ApplicationInfo class. You can use it to distinguish the system app version and the upgraded one.
System app will start with "/system/app" and upgraded app will start with "/data/app"
Try something like this
try {
ApplicationInfo appInfo = this.getPackageManager().getApplicationInfo("com.example.san", 0);
boolean isSystemApp = false;
if(appInfo.sourceDir.startsWith("/system/app")){ // You can use "contains" too
isSystemApp = true;
}
} catch (Exception e) {
e.printStackTrace();
}
Note: I didnt test it.. Hope it works
One proven solution is to pre-install an APK that on have the permission: RECEIVE_BOOT_COMPLETED
Then on the very first boot - you make a quick notation that you are a PREINSTALLED to whatever persistent storage you use, preferably add a token file.
You look for this token file on all your later APK versions to determine if the running copy originates from a device which had it pre-installed or not.
This solves the mayor issues:
1) Then its OK if the user updates you APK to the latest version, you can still read this token.
2) You don't have to maintain a separate APK on google play for the pre-installed community
3) You don't have to hustle with the OEM to install multiple APK when you actually only have one App.
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....
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?