首页 > 代码库 > Android研究之监听自身应用被卸载代码实现

Android研究之监听自身应用被卸载代码实现

1.通过jni实现函数


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//LOG宏定义
#define LOG_INFO(tag, msg) __android_log_write(ANDROID_LOG_INFO, tag, msg)
#define LOG_DEBUG(tag, msg) __android_log_write(ANDROID_LOG_DEBUG, tag, msg)
#define LOG_WARN(tag, msg) __android_log_write(ANDROID_LOG_WARN, tag, msg)
#define LOG_ERROR(tag, msg) __android_log_write(ANDROID_LOG_ERROR, tag, msg)
 
/* 内全局变量begin */
static char c_TAG[] = "onEvent";
static jboolean b_IS_COPY = JNI_TRUE;
 
jstring Java_com_example_uninstallself_Observer_register(JNIEnv* env,
        jobject thiz, jstring path, jstring url, jint version) {
    jstring tag = (*env)->NewStringUTF(env, c_TAG);
 
    //初始化log
    LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY),
            (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, "init OK"),
                    &b_IS_COPY));
 
    //fork子进程。以运行轮询任务
    pid_t pid = fork();
    if (pid < 0) {
        //出错log
        LOG_ERROR((*env)->GetStringUTFChars(env, tag, &b_IS_COPY),
                (*env)->GetStringUTFChars(env,
                        (*env)->NewStringUTF(env, "fork failed !!!"),
                        &b_IS_COPY));
    } else if (pid == 0) {
        //子进程注冊文件夹监听器
        int fileDescriptor = inotify_init();
        if (fileDescriptor < 0) {
            LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY),
                    (*env)->GetStringUTFChars(env,
                            (*env)->NewStringUTF(env,
                                    "inotify_init failed !!!"), &b_IS_COPY));
 
            exit(1);
        }
 
        int watchDescriptor;
 
        watchDescriptor = inotify_add_watch(fileDescriptor,
                (*env)->GetStringUTFChars(env, path, NULL), IN_DELETE);
        if (watchDescriptor < 0) {
            LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY),
                    (*env)->GetStringUTFChars(env,
                            (*env)->NewStringUTF(env,
                                    "inotify_add_watch failed !!!"),
                            &b_IS_COPY));
 
            exit(1);
        }
 
        //分配缓存。以便读取event。缓存大小=一个struct inotify_event的大小。这样一次处理一个event
        void *p_buf = malloc(sizeof(struct inotify_event));
        if (p_buf == NULL) {
            LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY),
                    (*env)->GetStringUTFChars(env,
                            (*env)->NewStringUTF(env, "malloc failed !!!"),
                            &b_IS_COPY));
 
            exit(1);
        }
        //開始监听
        LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY),
                (*env)->GetStringUTFChars(env,
                        (*env)->NewStringUTF(env, "start observer"),
                        &b_IS_COPY));
        //read会堵塞进程,
        size_t readBytes = read(fileDescriptor, p_buf,
                sizeof(struct inotify_event));
 
        //走到这里说明收到文件夹被删除的事件。注销监听器
        free(p_buf);
        inotify_rm_watch(fileDescriptor, IN_DELETE);
 
        //文件夹不存在log
        LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &b_IS_COPY),
                (*env)->GetStringUTFChars(env,
                        (*env)->NewStringUTF(env, "uninstalled"), &b_IS_COPY));
 
        if (version >= 17) {
            //4.2以上的系统因为用户权限管理更严格,须要加上 --user 0
            execlp("am", "am", "start", "--user", "0", "-a",
                    "android.intent.action.VIEW", "-d",
                    (*env)->GetStringUTFChars(env, url, NULL), (char *) NULL);
        } else {
            execlp("am", "am", "start", "-a", "android.intent.action.VIEW",
                    "-d", (*env)->GetStringUTFChars(env, url, NULL),
                    (char *) NULL);
        }
        //扩展:能够运行其它shell命令,am(即activity manager),能够打开某程序、服务,broadcast intent,等等
 
    } else {
        //父进程直接退出,使子进程被init进程领养,以避免子进程僵死
    }
 
    return (*env)->NewStringUTF(env, "Hello from JNI !");
}

2.定义UninstallObserver


1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class UninstallObserver {
 
    static{
        System.loadLibrary("observer");
    }
    /***
     *
     * @param path 须要监听的文件路径。可用 getApplicationContext().getFilesDir().getPath()
     * @param url 卸载调转http
     * @param version android.os.Build.VERSION.SDK_INT
     * @return
     */
    public static native String register(String path, String url, int version);
}

3.简单使用


1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
 
    Toast.makeText(getApplicationContext(),
            getApplicationContext().getFilesDir().getPath() + "," + Build.VERSION.SDK_INT, 1).show();
    long a = System.currentTimeMillis();
    String str = UninstallObserver.register(getApplicationContext().getFilesDir().getPath(), "http://www.baidu.com",
            android.os.Build.VERSION.SDK_INT);
    long b = System.currentTimeMillis();
    Toast.makeText(getApplicationContext(), str+","+(b-a), 1).show();
 
}


Android研究之监听自身应用被卸载代码实现