Today to interview, one side can, to the second side of the time is similar, finally came to a question, said that the 360 is unloaded after the jump to the specified feedback page, how to do? This has not been studied before, but this effect has been seen. It occurred to me that when uninstalling an app in Android, a broadcast would be sent, and we could receive the broadcast and then process it. As a result, he asked a rhetorical question: Is that OK? Then think about it, since he asked, there should be a problem, in thinking, found that there is a problem, when the application was unloaded, the reception of the broadcast after the processing of the logic to put it there to execute? All right, then it's over.
Back, Baidu a bit, sure enough, there seems to be related to the question of the answer, here will be their steps in refining a bit:
In fact, the core of this problem is that the application is unloaded, if you can do the subsequent code logic to continue to execute
Let's take a closer look at the scene and the process.
An application by the user uninstall is certainly a reason, and the developer may not be able to know this important reason, after all, the user will not be actively feedback suggestions, most of it is the use of uncomfortable on unloading, if you can be uninstalled after the user's feedback, it is very beneficial to developers to further improve the application. At present, as far as I know, the domestic Android application to achieve this function only 360 mobile phone defender, 360 tablet defender, then how to achieve this function?
We can change the implementation of the problem of unloading feedback to monitor whether they are uninstalled, only to know that they are uninstalled, can design the corresponding feedback processing process. The following list is the idea that I am studying this issue:
1, register Broadcastreceiver, monitor "Android.intent.action.PACKAGE_REMOVED" system broadcast
Result: NO. 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 issue, the main process is not, where to go onreceive () it?
2, if you can receive the "will unload XX package" system broadcast, in the main process is exited before the preemptive feedback processing is good, unfortunately there is no such system broadcast, but after investigation, but found a way to read the system log, the log contains the " Android.intent.action.DELETE "and your own package name means that you are going to be uninstalled.
Result: NO. Debugging found that this method has two defects, (1) Click the Uninstall button in the settings to issue this intent, the user has not been in the box to confirm the uninstall, (2) PM command Uninstall does not start this intent, means that is such as mobile phone security butler, Pea pod and other software uninstall, can not know in advance uninstall intent.
3, because the point of time is not easy to control, so simply do not rely on the system broadcast or log, considering that the uninstallation process will delete the "/data/data/package name" directory, we can use the thread to poll whether the directory exists, as a basis to determine whether it is uninstalled.
Result: NO. The same method 1, the main process exits, the corresponding thread must exit, the thread has not yet waited to determine the existence of the directory has been destroyed.
4, use the C-end process to poll the "/data/data/package name" directory exists
Result: YES. The C-side process fork out with the Java-side process will not be destroyed after the application is uninstalled.
The solution is OK, let's take a look at the code below:
/* Copyright (C) The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License") ; * You are not a use this file except in compliance with the License. * Obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * unless required by appli Cable law or agreed into writing, software * Distributed under the License is distributed on a "as is" BASIS, * without Warranties or CONDITIONS of any KIND, either express OR implied. * See the License for the specific language governing permissions and * limitations under the License. * */#include <jni.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include < android/log.h> #include <unistd.h> #include <sys/inotify.h> #include "com_example_uninstalldemos_ NativeClass.h "/* macro definition Begin *///Clear 0 Macro # Mem_zero (pDest, Destsize) memset (pDest, 0, destsize) #define LOG_TAG" OnEvent "/ /log macros Define # 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 LOGLOGD ("init start ...");//fork child process to perform polling task pid_t pid = fork (); if (PID < 0) {//Error LOGLOGD ("Fork failed ..."); else if (PID = = 0) {//Sub-process register "/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) ;} Allocates the cache so that the event is read, the cache size = the size of a struct inotify_event, such that a eventvoid *p_buf = malloc (sizeof (struct inotify_event)) is processed at a time; P_buf = = NULL) {logd ("malloc failed ..."); exit (1);} Start monitoring LOGD ("Start observer ..."); size_t readbytes = Read (FileDescriptor, p_buf,sizeof (struct inotify_event));// Read will block the process and go here to indicate the event that the directory was deleted, Logoff listener free (P_BUF); inotify_Rm_watch (FileDescriptor, in_delete);//directory does not exist LOGLOGD ("uninstall");//execute Command AM start-a android.intent.action.view-d http ://SHOUJI.360.CN/WEB/UNINSTALL/UNINSTALL.HTMLEXECLP ("AM", "AM", "Start", "-a", "Android.intent.action.VIEW", "-D", " Http://shouji.360.cn/web/uninstall/uninstall.html ", (char *) NULL),//4.2 above the system due to user rights management stricter, need to add--user 0//execlp (" AM " , "AM", "Start", "--user", "0", "-a",//"Android.intent.action.VIEW", "-D", "https://www.google.com", (char *) NULL);} else {//parent process exits directly so that the child process is adopted by the INIT process to avoid child process zombie}return (*env)->newstringutf (env, "Hello from JNI!");}
It's mostly used in Linux . INotify, This related content can self-baidu a bit ~ ~
Here is a very important knowledge, but also the key to solve the problem is that the parent process of Linux is dead, but the child process will not die, but was adopted by the INIT process. So when our application (process) is unloaded, but the sub-process of our fork is not destroyed, so we can put the above logic code here to do it. (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 {@Overridepublic 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 ") @Overridepublic void OnCreate () {sdcardlistener[] listenners = {new Sdcardlistener ("/data/data/ Com.example.uninstalldemos ", this), New Sdcardlistener (Environment.getexternalstoragedirectory () + 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 ();} */} @Overridepublic void OnDestroy () {for (Sdcardlistener listener:listenners) {listener.stopwatching ()}} @Overridepublic 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;} @Overridepublic void onEvent (int event, String path) {int action = event & Fileobserver.all_events;switch (action) {CA Se fileobserver.delete:log.i ("onEvent", "DELETE path:" + mPath + file.separator + path);//openbrowser (); Break;case Fileo Bserver. 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 ()}}}
Open a service, in this service we can see, with a very important class fileobserver, is also used to listen to the file changes, this and the above INotify function is similar. About this kind of concrete usage and introduction, can own Baidu Ah ~ ~
Run:
After we apply the installation, open log for the detection log:
ADB logcat-s onEvent
When we uninstall the app from the settings, the following screen pops up:
Note: Here I specifically said to uninstall the app from the Setup interface, because I don't jump when I use the Quick Uninstall app that comes with the Xiaomi phone. This specific reason remains to be solved (of course, 360 of this problem has not been solved.) )
Summarize:
The purpose of my writing this article and the only thing I learned from this process is that when the parent process dies, the subprocess does not die, so we can remember this knowledge point, which can be solved later by some logical operations like the application being unloaded.
The Android Uninstaller jumps to the specified feedback page after the program