I found that 360 security app after uninstall open their page in browser.
They can do it on all android versions (4., 5. and 6.*) and I don't understand how.
Maybe someone have any ideas? I know about same questions here and here and others but they still have no answers.
It's not a bug with inotify
because its works only on < 4.4.2 android, there is no other processes which listen for same bug in new way, I checked.
They had some magic in their lib eternity.so
How are App Uninstalls detected? You can detect app uninstalls by sending 'silent' push notifications. Silent push notifications are those notifications that aren't rendered on the user's device. You could send a silent push notification daily to all the devices with your app to track uninstalls.
Detection of app uninstalls can be made by sending silent push notifications. Notifications that are not created on the devices of the app users are called silent push notifications. You can keep track of app uninstalls by sending silent push notifications to all devices where your app is installed.
No. However, you can gauge your active user base by releasing an update and seeing how many people download it. Graphing it over time is useful data. Like Facebook, Twitter or Instagram too.
Do it correctly. Sometimes, when an app has outlived its usefulness, you'll want to uninstall it to make way for new ones. Uninstalling apps is easy enough: simply go to the Apps list, find the app, and hit the Uninstall button.
Let me try to clarify.
Before Android 4.4 we could use inotify
, which provides a mechanism for monitoring filesystem events, we create a daemon to monitor if a file we created in our app's directory is been deleted or our main app directory is deleted, which should happen when user uninstall the app, the JNI code will look something like this:
// initializes a new inotify instance and returns a file descriptor
fd = inotify_init();
// watch directory delete/create events
inotify_add_watch(fd, DIRECTORY, IN_DELETE | IN_CREATE);
__android_log_print(ANDROID_LOG_INFO, "TAG", "Watching [%s]", DIRECTORY);
// TODO: implement checkIfDeleted
if(checkIfDeleted()) {
// execute intent to open url
system("/system/bin/am start --user 0 -a android.intent.action.VIEW -d https://www...");
This no longer works because uninstall also kill group processes, attaching the relevant code from current source code
Take a look at git log
I need more time to investigate on unrooted device, 360security pack the app with specific architecture (a.k.a. ABI) and probably per API to reduce APK size, unfortunately apkmirror(.com) has only ARM available for download, I prefer to read x86, might edit this answer in the near future.
So far it seems the native code is creating files and playing with the locks to detect when the process is dead after the uninstall and then use JNI interface to invoke the callback.
To simplify, it seems it locks itself, and then join the synchronization module notify_and_waitfor
.
You can see a native code example for Android 5.0 here
NativeHelper source code (decompiled):
All method with keyword native
are implemented inside eternity
binary
package com.qihoo.eternity;
import com.qihoo.eternity.b;
public class NativeHelper {
static {
try {
System.loadLibrary((String)"eternity");
}
catch (Exception exception) {}
}
public native void look(String var1, String var2, String var3, String var4, String var5);
public void onU() {
b.a().g();
}
public native void pass(String var1, String var2);
public void peerDead() {
b.a().f();
}
public native void watch(String var1, String var2, String var3, String var4);
public native void watch2(String var1, String var2, String var3, String var4, String var5);
}
App references for NativeHelper:
com/qihoo/eternity/b.java:203:
new NativeHelper().look(b.this.h.getPackageName(), b.b((b)b.this).f, string2, b.b(b.this.i), string3);
com/qihoo/eternity/b.java:224:
new NativeHelper().watch(new File(file, "a1").getAbsolutePath(), new File(file, "a2").getAbsolutePath(), new File(file, "a3").getAbsolutePath(), new File(file, "a4").getAbsolutePath());
com/qihoo/eternity/b.java:264:
new NativeHelper().watch(new File(file, "a2").getAbsolutePath(), new File(file, "a1").getAbsolutePath(), new File(file, "a4").getAbsolutePath(), new File(file, "a3").getAbsolutePath());
com/qihoo/eternity/b.java:518:
new NativeHelper().pass(this.a, this.b);
com/qihoo/eternity/b.java:563:
new NativeHelper().watch2(new File(file, "b1").getAbsolutePath(), new File(file, "b2").getAbsolutePath(), new File(file, "b3").getAbsolutePath(), new File(file, "b4").getAbsolutePath(), b.this.h.getDir("lib", 0).getAbsolutePath());
com/qihoo/eternity/b.java:588:
new NativeHelper().watch2(new File(file, "b2").getAbsolutePath(), new File(file, "b1").getAbsolutePath(), new File(file, "b4").getAbsolutePath(), new File(file, "b3").getAbsolutePath(), b.this.h.getDir("lib", 0).getAbsolutePath());
One solution will be to include the shared object eternity.so
in your JNI folder and implement NativeHelper.onU
method :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With