NDK开发汇总
ACTION_PACKAGE_REMOVED
ACTION_PACKAGE_REMOVED
皮之不存毛将焉附
内存 --》
监听 别人
卸载 系统log (正在被安装的包程序不能接收到这个广播), 监听自身
Java线程 轮训 监听 监听/data/data/{package-name}目录是否存在
C进程 监听/data/data/{package-name}目录是否存在 跳转到网页
上述4种方式均不能监听自身的卸载,可以用下面的方式实现
监听 /data/data/{package-name}目录是否存在
从前四种方案可以看到,单纯的Java层代码是无法监听自身卸载的。既然Java层无法实现,我们试着使用C语言在底层实现。
借助Linux进程fork出来的C进程在应用被卸载后不会被销毁,监听/data/data/{package-name}目录是否存在,如果不存在,就证明应用被卸载了。
加载
init native
android-6.0.0_r1\frameworks\base\core\jni
//初始化监听
private native int init();
private native int startWatching(int fd, String path, int mask);
fork(); 开两个进程
一个函数 1
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。
然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
它是一个内核用于通知用户空间程序文件系统变化的机制。
结构中的 wd 为被监视目标的 watch 描述符,
mask 为事件类型
len 为 name字符串的长度
name 为被监视目标的路径名,该结构的 name 字段为一个桩
它只是为了用户方面引用文件名,文件名是变长的,
buf 是一个 inotify_event 结构的数组指针,
BUF_LEN 指定要读取的总长度,
buf 大小至少要不小于 BUF_LEN,
该调用返回的事件数取决于 BUF_LEN 以及事件中文件名的长度
。Len 为实际读去的字节数,即获得的事件的总长度。
IN_ACCESS,即文件被访问
IN_MODIFY,文件被 write
IN_ATTRIB,文件属性被修改,如 chmod、chown、touch 等
IN_CLOSE_WRITE,可写文件被 close
IN_CLOSE_NOWRITE,不可写文件被 close
IN_OPEN,文件被 open
IN_MOVED_FROM,文件被移走,如 mv
IN_MOVED_TO,文件被移来,如 mv、cp
IN_CREATE,创建新文件
IN_DELETE,文件被删除,如 rm
IN_DELETE_SELF,自删除,即一个可执行文件在执行时删除自己
IN_MOVE_SELF,自移动,即一个可执行文件在执行时移动自己
IN_UNMOUNT,宿主文件系统被 umount
IN_CLOSE,文件被关闭,等同于(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
IN_MOVE,文件被移动,等同于(IN_MOVED_FROM | IN_MOVED_TO)
注:上面所说的文件也包括目录。
作业
#include
int main(int argc, char* argv[]) {
fork();
fork() && fork() || fork();
fork();
} 求 进程 数量
Intent
am start -n com.yuanhh.app/.MainActivity
am 不需要弹选择框
#include
#include
#include
#include
#include
#include
#include
#define LOG_TAG "tuch"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
extern "C"
{
JNIEXPORT void JNICALL
Java_com_dongnao_ls19uninstall_MainActivity_stringFromJNI(
JNIEnv *env,
jobject obg,jint sdk,jstring path) {
// pid_t pid=fork();
// if (pid < 0) {
// LOGD("fork失败");
//// 系统fork()
// } else if (pid > 0) {
// LOGD("父进程");
// } else{
// LOGD("子进程");
// // 初始化 inotify
//
// int observer = open(observerFile, O_RDONLY);
// if (observer == -1) {
// //不存在就创建
// observer = open(observerFile, O_CREAT);
// }
// int fileDescriple = inotify_init();
// int watch=inotify_add_watch(fileDescriple, observerFile, IN_DELETE_SELF);
// if (watch < 0) {
// LOGD("监听失败");
// }
// void *p_buf=malloc(sizeof(struct inotify_event));
// // 阻塞式函数 anr
// size_t readBytes=read(fileDescriple,p_buf, sizeof(struct inotify_event));
//// 主进程 1
//// 执行到下面来了 文件发生了改变 用户卸载了 app
// LOGD("监听类型 %d ,%d",((struct inotify_event *) p_buf)->mask,IN_DELETE_SELF);
// if (((struct inotify_event *) p_buf)->mask == IN_DELETE_SELF) {
////// 覆盖安装
//// FILE *app_file = fopen("/data/data/com.dongnao.ls19uninstall", "r");
//// if (app_file == NULL) {
//// // 删除app 移除监听
//// inotify_rm_watch(fileDescriple, watch);
//// } else{
//// // 覆盖安装 重新进行监听
//// fclose(app_file);
//// FILE *p_observelFile = fopen(observerFile, "w");
//// int watchDescip=inotify_add_watch(fileDescriple, observerFile, IN_DELETE_SELF);
//// }
// }
// LOGD("跳转网页");
//// 铁了心要删除app sdk 17 am 设置到环境变量 多用户的操作
// if (sdk < 17) {
// execlp("am", "am", "start", "-a", "android.intent.action.VIEW", "-d",
// "http://www.baidu.com",NULL);
//
// } else{
// execlp("am", "am", "start","--user","0","-a", "android.intent.action.VIEW", "-d",
// "http://www.baidu.com",NULL);
// }
//
// }
}
JNIEXPORT void JNICALL
Java_com_dongnao_ls19uninstall_MainActivity_load__ILjava_lang_String_2(JNIEnv *env,
jobject instance, jint sdk,
jstring path_) {
const char *path = env->GetStringUTFChars(path_, 0);
pid_t pid=fork();
if (pid < 0) {
LOGD("fork失败");
// 系统fork()
} else if (pid > 0) {
LOGD("父进程");
} else {
LOGD("子进程");
// 初始化 inotify
int fileDescriple = inotify_init();
int watch=inotify_add_watch(fileDescriple, path, IN_DELETE_SELF);
void *p_buf=malloc(sizeof(struct inotify_event));
// 阻塞式函数 anr
size_t readBytes=read(fileDescriple,p_buf, sizeof(struct inotify_event));
inotify_rm_watch(fileDescriple, watch);
LOGD("跳转网页");
// 铁了心要删除app sdk 17 am 设置到环境变量 多用户的操作
if (sdk < 17) {
execlp("am", "am", "start", "-a", "android.intent.action.VIEW", "-d",
"http://www.baidu.com",NULL);
} else{
execlp("am", "am", "start","--user","0","-a", "android.intent.action.VIEW", "-d",
"http://www.baidu.com",NULL);
}
}
// TODO
env->ReleaseStringUTFChars(path_, path);
}
}
● -a : 指定Intent action, 实现原理Intent.setAction();
● -n : 指定组件名,格式为{包名}/.{主Activity名},实现原理Intent.setComponent();
● -d
● -t
● -c [-c ] …]:指定Intent category,实现原理Intent.addCategory()
● -p : 指定包名,实现原理Intent.setPackage();
● -f : 添加flags,实现原理Intent.setFlags(int ),紧接着的参数必须是int型;
基本类型
参数-e/-es-esn-ez-ei-el-ef-eu-ecn类型String(String)nullbooleanintlongfloaturicomponent
比如参数es是Extra String首字母简称,实例:
intent.putExtra(“website”,“website gityuan.com”)
am start -n com.dongnao.app/.MainActivity -es website gityuan.com
intent.put
比如参数efal,是Extra float Array List首字母简称,多个value值之间以逗号隔开,实例:
am start -n comdongnao.app/.MainActivity -efal nums 1.2,2.2
此处-es website gityuan.com,等价于Intent.putExtra(“website”, “gityuan.com”);
AM四大组件 所有跳转问题
AM 命令
跳转 模块