Android uninstalls the program and jumps to the specified feedback page.

Source: Internet
Author: User

Android uninstalls the program and jumps to the specified feedback page.

When I went to the interview today, I was fine. It was almost the same as when I got to the second place. I finally came up with a question, saying that the 360 was uninstalled and would jump to the specified feedback page. How did I get it? I have not studied this before, but I have seen this effect. At that time, we thought that a broadcast will be sent when the app is uninstalled in Android. We can receive the broadcast and process it. As a result, he asked a rhetorical question: is this all right? Then think about it. Now that he has asked this question, there should be a problem. When I think about it, I find that there is indeed a problem. When the application is uninstalled, where does the logic code after receiving the broadcast processing be executed? Okay, then there's no drama ~~

When I came back, I went to Baidu. As a result, there seemed to be answers to relevant questions on the Internet. Here I will refine their steps:


In fact, the core of this problem is: The application is uninstalled. If the subsequent code logic can be executed


Let's analyze the scenario and process carefully.

There must be a reason for an application to be uninstalled by users, but developers may not be able to learn this important reason. After all, users seldom take the initiative to provide suggestions, and most of them unload the application if it is not used properly, if some user feedback can be obtained after being uninstalled, It is very advantageous for developers to further improve the application. Currently, as far as I know, only 360 mobile guard and 360 tablet guard are implemented in Android apps in China. How can this function be implemented?

We can convert the problem of implementing the unload feedback to whether the listener is uninstalled. Only when we know that the listener is uninstalled can we design the corresponding feedback processing process. The following lists my thoughts on this issue:

1. Register BroadcastReceiver and listen to "android. intent. action. PACKAGE_REMOVED" system broadcast.
Result: NO. If no code is written, analyze it directly. The first step of uninstallation is to exit the main process of the current application. This broadcast is issued only after the uninstallation is complete. At this time, no primary process is available, which onReceive?

2. If you receive the system broadcast "the XX packet will be uninstalled", you can take the lead to handle the feedback before the main process is exited. Unfortunately, this system broadcast is unavailable. However, after investigation, however, we found a way to read the system log when the log contains "android. intent. action. DELETE and its package name, which means that you are about to be uninstalled.
Result: NO. This method has two defects during debugging. (1) Click the detach button in the settings to issue the Intent. At this time, the user has not confirmed uninstalling it in the pop-up box; (2) when the pm command uninstalls the Intent, it means that the Intent of uninstallation cannot be known in advance when software such as mobile phone security manager and pea pod are uninstalled.

3. Because the time point is not easy to control, it simply does not rely on system broadcast or log. Considering that the unmount process will delete the "/data/package name" directory, we can use threads to directly check whether the directory exists and determine whether it is uninstalled.
Result: NO. In the same method 1, the main process exits, and the corresponding thread is bound to exit. The thread is destroyed before determining whether the directory exists.

4. Switch to the C-end process to check whether the "/data/package name" directory exists.
Result: YES. The C-end process that comes out of the Java-side process fork will not be destroyed after the application is uninstalled.


The solution is fixed. Let's take a look at the code below:

/** Copyright (C) 2009 The Android Open Source Project ** Licensed under the Apache License, Version 2.0 (the "License "); * you may not use this file before t in compliance with the License. * You may be obtain a copy of the License at ** http://www.apache.org/licenses/LICENSE-2.0 ** Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "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
 
  
# Include
  
   
# Include
   
    
# Include
    
     
# Include
     
      
# Include
      
        # Include "com_example_uninstalldemos_NativeClass.h"/* macro definition begin * // clear 0 macro # 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 initialize (JNIEnv * env, jobject thiz) {// initialize logd ("init start... "); // fork sub-process to run the round robin task pi D_t pid = fork (); if (pid <0) {// error logd ("fork failed... ");} else if (pid = 0) {// subprocess registration"/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/com. example. uninstalldemos ", IN_DELETE); LOGD (" watchDescriptor = % d ", watchDescripto R); if (watchDescriptor <0) {LOGD ("inotify_add_watch failed... "); exit (1);} // allocate the cache to read the event. The cache size is equal to the size of a struct inotify_event, processing an eventvoid * p_buf = malloc (sizeof (struct inotify_event); if (p_buf = NULL) {LOGD ("malloc failed... "); exit (1) ;}// start listening to LOGD (" start observer... "); size_t readBytes = read (fileDescriptor, p_buf, sizeof (struct inotify_event); // read will block the process. Here, it indicates that the directory is deleted, cancel listener free (p_buf); inotif Y_rm_watch (fileDescriptor, IN_DELETE); // The directory does not contain logd ("uninstall"); // execute the 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); // more than 4.2 of the system due to stricter user permission management, -- user 0 // execlp ("am", "am", "start", "-- user", "0", "-a", // "android. inte Nt. action. VIEW ","-d "," https://www.google.com ", (char *) NULL);} else {// The parent process exits directly so that the child process is adopted by the init process, to prevent sub-processes from freezing} return (* env)-> NewStringUTF (env, "Hello from JNI! ");}
      
     
    
   
  
 

Inotify in Linux is mainly used here. You can refer to Baidu for related content ~~

There is a very important knowledge here, and it is also the key to solve this problem. In Linux, the parent process is dead, but the child process is not dead, but adopted by the init process. So when our application (process) is uninstalled, but our fork sub-process will not be destroyed, so we can put the above logic code here. (Learned)


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/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) {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 retry runtime.getruntime(cmd.exe c (cmd);} catch (Throwable t) {t. printStackTrace ();}}}
Start a service. In this service, we can see that a very important FileObserver class is used to listen for file changes, which is similar to the inotify function above. For specific usage and introduction of this class, you can use Baidu ~~


Run:

After the application is installed, open the log for detection:

Adb logcat-s onEvent



When we detach an application from settings, the following page is displayed:


Note: I specifically mentioned here to uninstall the application from the setting interface, because it does not jump when I use the quick uninstall app that comes with Xiaomi mobile phone. The specific cause remains to be solved (of course, this problem of 360 has not been solved ..)


Summary:

The purpose of writing this article and the only knowledge point I learned from this process is that when the parent process disappears, the child process will not die, so we can remember this knowledge point, in the future, some logical operations such as after the application is uninstalled can be solved in this way.






Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.