Many people may ask: 360 after being unloaded will jump to the specified feedback page, how to do it?
The core of the problem is that the application is uninstalled, and if the subsequent code logic continues to execute
Let's take a closer look at the scene and the process.
An application that is unloaded by the user must be justified, and developers may not be able to understand this important reason, after all, users will rarely actively feedback suggestions, most of it is used to unload, if you can get the user after the unloading of some feedback, it is very beneficial for developers to further improve the application. As far as I know, the domestic Android application to achieve this function only 360 mobile phone guards, 360 tablet guards, then how to achieve this function?
We can change the implementation of the problem of unloading feedback to monitor whether they are unloaded, only to know that they have been unloaded, we can design the corresponding feedback processing process. The following list is the way I look at this problem:
1, register Broadcastreceiver, monitor "Android.intent.action.PACKAGE_REMOVED" system broadcast
Result: NO. Not write code, direct analysis, uninstall the first step is to exit the current application of the main process, and this broadcast is already uninstalled after the completion of the OnReceive, when the main process is gone, where to go?
2, if you can receive "will uninstall XX package" System broadcast, before the main process is withdrawn before the preemptive feedback processing is good, but no such system broadcast, but after investigation, but found a way to read the system log, the log contains " Android.intent.action.DELETE "and your own package name means that you are going to be unloaded.
Result: NO. This method is found to have two defects during debugging. (1) Click the Uninstall button in the Setup to issue this intent, the user has not yet confirmed in the Bomb box Uninstall; (2) PM command uninstall do not start this intent, means to be such as mobile phone security butler, Pea pod and other software uninstall, can not know the unloading intention in advance.
3, because the point of time is not easy to control, so simply do not rely on the system broadcast or log, considering the uninstall process will delete the "/data/data/package name" directory, we can use the thread directly polling whether the directory exists, as a basis to determine whether they were unloaded.
Result: NO. With Method 1, the main process exits, the corresponding thread is bound to exit, and the thread has not yet been destroyed to determine if the directory exists.
4, switch to the C-side process polling "/data/data/package name" directory exists
Result: YES. The C-End process fork out with Java-side processes is not destroyed after the application is uninstalled.
The solution is OK, let's take a look at the code:
#include <jni.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <andr oid/log.h> #include <unistd.h> #include <sys/inotify.h> #include "com_example_uninstalldemos_nativecl
Ass.h "/* macro definition Begin//Clear 0 Macros #define Mem_zero (pdest, Destsize) memset (pdest, 0, destsize) #define LOG_TAG" OnEvent " Log macro definition #define LOGD (FMT, args ...) __android_log_print (Android_log_info, Log_tag, FMT, # #args) Jniexport jstring Jnicall Java_com_example_uninstalldemos_nativeclass_init (jnienv* env, jobject thiz) {//Initialize log logd ("init start ...
.");
Fork the child process to perform a polling task pid_t pid = fork ();
if (PID < 0) {//error log logd ("Fork failed ..."); else if (PID = = 0) {//Subprocess registers "/data/data/pym.test.uninstalledobserver" directory listener int filedescriptor = Inotify_init ()
;
if (FileDescriptor < 0) {logd ("Inotify_init failed ...");
Exit (1);
int watchdescriptor; Watchdescriptor = InotIfy_add_watch (FileDescriptor, "/data/data/com.example.uninstalldemos", in_delete);
LOGD ("watchdescriptor=%d", watchdescriptor);
if (Watchdescriptor < 0) {logd ("Inotify_add_watch failed ...");
Exit (1); ///Allocate cache to read event, cache size = size of a struct inotify_event, which handles an event void *p_buf = malloc sizeof (struct inotify_eve
NT));
if (p_buf = = NULL) {logd ("malloc failed ...");
Exit (1);
//Start listening LOGD ("Start observer ...");
size_t readbytes = Read (FileDescriptor, p_buf,sizeof (struct inotify_event));
Read will block the process, go here to explain the receipt of the directory was deleted event, Logout listener free (P_BUF);
Inotify_rm_watch (FileDescriptor, in_delete);
Directory does not exist log logd ("Uninstall"); Execute command am start-a android.intent.action.view-d http://shouji.360.cn/web/uninstall/uninstall.html execlp ("AM" , "AM", "Start", "-a", "Android.intent.action.VIEW", "D", "http://shouji.360.cn/web/uninstall/uninstall.html", (c
Har *) NULL); More than 4.2 of systems dueUser Rights Management is more stringent and requires the addition of--user 0//EXECLP ("AM", "AM", "Start", "--user", "0", "a",//"Android.intent.action.VIEW", "D",
"Https://www.google.com", (char *) NULL);
else {//the parent process exits directly, allowing the subprocess to be adopted by the INIT process to avoid child process zombie} return (*ENV)->newstringutf (env, "Hello from JNI!");
}
This is mainly used in the Linux inotify, the relevant content can be its own Baidu ~ ~
Here is a very important knowledge, but also the key to solve this problem is that the Linux parent process is dead, but the child process is not dead, but was adopted by the INIT process. So when we uninstall the application (process), our fork is not destroyed, so the logical code above can be put here. (studied)
Android Application code:
Myactivity.java
Package Com.example.uninstalldemos;
Import android.app.Activity;
Import android.content.Intent;
Import Android.os.Bundle;
Import Android.util.Log;
public class MyActivity extends activity {
@Override public
void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (r.layout.activity_main);
Intent Intent = new Intent (this, sdcardlistenser.class);
StartService (intent);
Nativeclass nativeobj = new Nativeclass ();
Nativeobj.init ();
}
static {
log.d ("OnEvent", "Load Jni lib");
System.loadlibrary ("Hello-jni");
}
Sdcardlistenser.java
Package Com.example.uninstalldemos;
Import Android.annotation.SuppressLint;
Import Android.app.Service;
Import Android.content.Context;
Import android.content.Intent;
Import Android.net.Uri;
Import android.os.Environment;
Import Android.os.FileObserver;
Import Android.os.IBinder;
Import Android.util.Log;
Import Java.io.File;
Import java.io.IOException;
public class Sdcardlistenser extends Service {sdcardlistener[] listenners; @SuppressLint ("Sdcardpath") @Override public void OnCreate () {sdcardlistener[] listenners = {new SD Cardlistener ("/data/data/com.example.uninstalldemos", this), New Sdcardlistener (Environment.getexternalstoragedir
Ectory () + File.separator + "1.txt", this)};
This.listenners = listenners;
LOG.I ("OnEvent", "=========oncreate============");
for (Sdcardlistener listener:listenners) {listener.startwatching (); File File = new file (environment.getexternalstoragedirectory () + File.separator + "1.txt");
LOG.I ("OnEvent", "dddddddddddddddddddddd ncreate============");
if (file.exists ()) File.delete ();
/*try {file.createnewfile ();
catch (IOException e) {e.printstacktrace (); }*/} @Override public void OnDestroy () {for (Sdcardlistener listener:listenners) {Listener.sto
Pwatching ();
@Override public IBinder onbind (Intent Intent) {return null;
} class Sdcardlistener extends Fileobserver {private String mpath;
Private final context Mcontext;
Public Sdcardlistener (String parentpath, Context ctx) {super (Parentpath);
This.mpath = Parentpath;
This.mcontext = CTX;
@Override public void onEvent (int event, String path) {int action = event & fileobserver.all_events; Switch (action) {case FILEOBSERVER.DELETE:LOG.I ("OnEvent", "DELETE path:" + MPath + file.separator +
path); OpenbrowseR ();
Break
Case FILEOBSERVER.MODIFY:LOG.I ("OnEvent", "Change Directory" + mpath + file.separator + path);
Break
Case FILEOBSERVER.CREATE:LOG.I ("OnEvent", "Create file" + MPath + file.separator + path);
Break
Default:break;
} protected void Openbrowser () {uri uri = uri.parse ("http://aoi.androidesk.com");
Intent Intent = new Intent (Intent.action_view, URI);
Mcontext.startactivity (Intent);
public void Exeshell (String cmd) {try {runtime.getruntime (). exec (CMD);
catch (Throwable t) {t.printstacktrace ();
}
}
}
To open a service, we can see in this service that a very important class fileobserver is used to monitor the change of the file, which is similar to the INotify function above. On the specific use of this class and introduction, you can own Baidu Ah ~ ~
Run:
After the installation, we will open log for detection log: