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();
 
}

p=2010">本文參考资料

Android研究之监听自身应用被卸载代码实现的更多相关文章

  1. Android应用如何监听自己是否被卸载及卸载反馈功能的实现

    一个应用被用户卸载肯定是有理由的,而开发者却未必能得知这一重要的理由,毕竟用户很少会主动反馈建议,多半就是用得不爽就卸,如果能在被卸载后获取到用户的一些反馈,那对开发者进一步改进应用是非常有利的.目前 ...

  2. Android 短信监听及用途分析

    监听系统短信这个只能作为一个技术点来研究下,读者可能在工作中可能不会哦涉及到,一般的应用软件也不会有这个需求 但是作为程序员呢,多了解一下也是好的. Android 监听系统短信有什么用? 1.对系统 ...

  3. Android 手势水平监听判断

    package com.zihao.ui; import com.zihao.R; import android.os.Bundle; import android.app.Activity; imp ...

  4. Android中如何监听GPS开启和关闭

    转自 chenming 原文 Android中如何监听GPS开启和关闭   摘要: 本文简单总结了如何监听GPS开关的小技巧 有时需要监听GPS的开关(这种需求并不多见).实现的思路是监听代表 GPS ...

  5. Android手机上监听短信的两种方式

    Android手机上监听短信有两种方式: 1. 接受系统的短信广播,操作短信内容. 优点:操作方便,适合简单的短信应用. 缺点:来信会在状态栏显示通知信息. AndroidManifest.xml: ...

  6. 【Android】Android 监听apk安装替换卸载广播

    [Android]Android 监听apk安装替换卸载广播 首先是要获取应用的安装状态,通过广播的形式 以下是和应用程序相关的Broadcast Action ACTION_PACKAGE_ADDE ...

  7. android的电话监听

    android的电话监听 新建一个项目,结构图如下: PhoneService: package com.demo.tingdianhua; import android.app.Service; i ...

  8. Android零基础入门第34节:Android中基于监听的事件处理

    原文:Android零基础入门第34节:Android中基于监听的事件处理 上一期我们学习了Android中的事件处理,也详细学习了Android中基于监听的事件处理,同时学会了匿名内部类形式,那么本 ...

  9. Android实现网络监听

    一.Android Wifi常用广播 网络开发中主体会使用到的action: ConnectivityManager.CONNECTIVITY_ACTION WifiManager.WIFI_STAT ...

随机推荐

  1. Android 开发笔记___FrameLayout

    xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:la ...

  2. javascript 备忘 细节 相关

    DOMContentLoaded事件触发时机,即dom tree完成但页面未必渲染完毕.   var a = [1,2,3,4]; var length = a.length; alert((leng ...

  3. NoSQL:linux操作memcached

    缓存数据库 一 NoSQL简介 NoSQL(NoSQL = Not Only SQL ),意即"不仅仅是SQL",泛指非关系型的数据库,随着互联网web2.0网站的兴起,传统的关系 ...

  4. IntelliJ配置jenkins服务的Crumb Data

    近期在做jenkins测试,IntelliJ并没有自动安装jenkins服务器,因此需要自己添加,但是如果不配置Crumb Data,jenkins的服务就不能使用. 首先在服务器中开启CSRF服务, ...

  5. 学习RocketMQ (一) 安装并且启动MQ

    1.使用RocketMQ 的 软件要求 64bit OS, Linux/Unix/Mac is recommended;64bit JDK 1.8+;Maven 3.2.xGit 1)安装Linux ...

  6. 身为运维的你,怎么掌握python才不会失业

    以前,我们都说Python是运维工程师的未来:现在,为什么大家都说不会Python的运维都将失业?运维必须懂开发,特别是python开发,已经形成大家的共识,不懂开发的运维,路会越走越窄. 而现在的情 ...

  7. httpwebrequest 用GET方法时报无法发送具有此谓词类型的内容正文

    如下一段小程序,运行结果报无法发送具有此谓词类型的内容正文的错误,其实原因很简单,因为用的是GET的方式进行提交,而GetRequestStream()是用来在post提交的时候写post的内容的流, ...

  8. 基础教程:视图中的ASP.NET Core 2.0 MVC依赖注入

    问题 如何在ASP.NET Core MVC Views中注入和使用服务. 解 更新 启动 类来为MVC添加服务和中间件. 添加一项服务 添加一个Controller,返回 ViewResult. 添 ...

  9. 使用dropwizard(3)-加入DI-dagger2

    前言 习惯了Spring全家桶,对spring的容器爱不释手.使用dropwizard,看起来确实很轻,然而,真正使用的时候不得不面临一个问题.我们不可能一个resource就能把所有的业务逻辑囊括! ...

  10. Mysql的学习笔记(一)--检验数据库是否安装成功以及一些入门的简单的dos命令

    一:如何检验数据库是否安装成功: 1:以管理员的身份打开命令提示符,具体如何用管理员的身份打开请参考下面 https://jingyan.baidu.com/article/e73e26c0f87c2 ...