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