[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs     diff=csharp\n*.sln    merge=union\n*.csproj merge=union\n*.vbproj merge=union\n*.fsproj merge=union\n*.dbproj merge=union\n\n# Standard to msysgit\n*.doc\t diff=astextplain\n*.DOC\t diff=astextplain\n*.docx diff=astextplain\n*.DOCX diff=astextplain\n*.dot  diff=astextplain\n*.DOT  diff=astextplain\n*.pdf  diff=astextplain\n*.PDF\t diff=astextplain\n*.rtf\t diff=astextplain\n*.RTF\t diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": "# Windows image file caches\r\nThumbs.db\r\nehthumbs.db\r\n\r\n# Folder config file\r\nDesktop.ini\r\n\r\n# Recycle Bin used on file shares\r\n$RECYCLE.BIN/\r\n\r\n# Windows Installer files\r\n*.cab\r\n*.msi\r\n*.msm\r\n*.msp\r\n\r\n# =========================\r\n# Operating System Files\r\n# =========================\r\n\r\n# OSX\r\n# =========================\r\n\r\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\r\r\n\n# Thumbnails\n._*\n\n# Files that might appear on external disk\n.Spotlight-V100\n.Trashes\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n"
  },
  {
    "path": ".project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>UnInstallDemo</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>com.android.ide.eclipse.adt.ApkBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>\n\t\t\t<triggers>auto,full,incremental,</triggers>\n\t\t\t<arguments>\n\t\t\t\t<dictionary>\n\t\t\t\t\t<key>LaunchConfigHandle</key>\n\t\t\t\t\t<value>&lt;project&gt;/.externalToolBuilders/New_NDK.launch</value>\n\t\t\t\t</dictionary>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>com.android.ide.eclipse.adt.AndroidNature</nature>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.lzyblog.uninstalldemo\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.1\" >\n\n    <uses-sdk\n        android:minSdkVersion=\"10\"\n        android:targetSdkVersion=\"19\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@drawable/ic_launcher\"\n        android:label=\"@string/app_name\" >\n        <activity\n            android:name=\".UninstalledObserverActivity\"\n            android:label=\"@string/app_name\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n    </application>\n\n</manifest>"
  },
  {
    "path": "README.md",
    "content": "## Android应用监听自己是否被卸载，卸载后弹出反馈网页\n\n### 在前人的基础上有这些解决方案\n1. 监听卸载广播，只能监听到别人卸载。自己被卸载的时候，早就收不到广播了。\n2. 监听log。这样听起来很靠谱，能稳定监听到，但是发送操作不靠谱。\n3. 监听/data/data/<package name>。当Android卸载应用的时候，会先删除这里的文件。可以轮询监听，可以优化成unix文件监听方式，，这样只用等待文件监听服务的回调。\n\n### 采用了第3种解决办法，并对其进行了优化：\n#### 问题：\n监听/data/data/<package name>这个目录，还存在以下几个问题：\n\n1. 清除数据、插拔USB线、覆盖安装等操作引起程序误判卸载。\n2. 重复监听的问题。\n3. 用户将已在Internal SD卡安装好的应用移动到external SD卡，导致监听不正常。\n\n#### 原因：\n1. 由于inotify_add_watch(fileDescriptor, path, IN_DELETE)这个函数会监听path目录下所有文件的删除操作导致。\n2. 重复调用JNI的init方法\n3. 暂时未修复\n\n#### 解决方法：\n1. 监听不应该针对整个文件夹，而是某个文件。\n2. 重复监听的问题，都可以通过加文件锁来防止\n\n详细方案可参考我的博文：[Android监听自己是否被卸载](http://lzyblog.com/2015/01/09/Android%E5%BA%94%E7%94%A8%E7%9B%91%E5%90%AC%E8%87%AA%E5%B7%B1%E6%98%AF%E5%90%A6%E8%A2%AB%E5%8D%B8%E8%BD%BD%EF%BC%8C%E5%81%9A%E5%8F%8D%E9%A6%88%E7%BB%9F%E8%AE%A1/)\n\n参考自:\n\nhttps://github.com/sevenler/Uninstall_Statics\n\nhttp://www.cnblogs.com/zealotrouge/p/3157126.html\n\nhttp://www.cnblogs.com/zealotrouge/p/3159772.html\n\nhttp://www.cnblogs.com/zealotrouge/p/3182617.html"
  },
  {
    "path": "jni/Android.mk",
    "content": "# Copyright (C) 2009 The Android Open Source Project\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nLOCAL_PATH := $(call my-dir)\n\ninclude $(CLEAR_VARS)\n\nLOCAL_MODULE    := uninstalled_observer\nLOCAL_SRC_FILES := UninstalledObserver.c\n\nLOCAL_C_INCLUDES := $(LOCAL_PATH)/include\nLOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog\n\ninclude $(BUILD_SHARED_LIBRARY)\n"
  },
  {
    "path": "jni/UninstalledObserver.c",
    "content": "\n/*\n * Copyright (C) 2009 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTICE:cļҪĶֱʶ TODO1  TODO2\n */\n#include<jni.h>\n#include<stdlib.h>\n#include<stdio.h>\n#include<string.h>\n#include<unistd.h>\n#include<fcntl.h>\n#include<sys/inotify.h>\n#include<sys/stat.h>\n\n#include<android/log.h>\n\n/* 궨begin */\n//0\n#define MEM_ZERO(pDest, destSize) memset(pDest, 0, destSize)\n\n//LOG궨\n#define LOG_INFO(tag, msg) __android_log_write(ANDROID_LOG_INFO, tag, msg)\n#define LOG_DEBUG(tag, msg) __android_log_write(ANDROID_LOG_DEBUG, tag, msg)\n#define LOG_WARN(tag, msg) __android_log_write(ANDROID_LOG_WARN, tag, msg)\n#define LOG_ERROR(tag, msg) __android_log_write(ANDROID_LOG_ERROR, tag, msg)\n\n\n/* ȫֱbegin */\nstatic char TAG[] = \"UninstalledObserverActivity.init\";\nstatic jboolean isCopy = JNI_TRUE;\n\n//--TODO1--------------------ҪĳԼapkİ------------------------------------\nstatic const char APP_DIR[] = \"/data/data/com.lzyblog.uninstalldemo\";\nstatic const char APP_FILES_DIR[] = \"/data/data/com.lzyblog.uninstalldemo/files\";\nstatic const char APP_OBSERVED_FILE[] = \"/data/data/com.lzyblog.uninstalldemo/files/observedFile\";\nstatic const char APP_LOCK_FILE[] = \"/data/data/com.lzyblog.uninstalldemo/files/lockFile\";\n/* ȫֱ */\n\n/*-------TODO2-----------------------\n * Class:     ҪĳԼapp\n * Method:    init\n * Signature: ()V\n * return: ӽpid\n */\nJNIEXPORT int JNICALL Java_com_lzyblog_uninstalldemo_UninstalledObserverActivity_init(JNIEnv *env, jobject obj, jstring userSerial, jstring website)\n{\n    jstring tag = (*env)->NewStringUTF(env, TAG);\n\tchar* websiteStr=(char*) (*env)->GetStringUTFChars(env, website, NULL);\n\n    LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n            , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"init observer\"), &isCopy));\n\n    // forkӽִ̣ѯ\n    pid_t pid = fork();\n    if (pid < 0)\n    {\n        LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)\n                , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"fork failed !!!\"), &isCopy));\n\n        exit(1);\n    }\n    else if (pid == 0)\n    {\n\t    LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n\t            , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"fork Success !!!\"), &isCopy));\n        // ļļвڣ\n        FILE *p_filesDir = fopen(APP_FILES_DIR, \"r\");\n        if (p_filesDir == NULL)\n        {\n            int filesDirRet = mkdir(APP_FILES_DIR, S_IRWXU | S_IRWXG | S_IXOTH);\n            if (filesDirRet == -1)\n            {\n                LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)\n                        , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"mkdir failed !!!\"), &isCopy));\n\n                exit(1);\n            }\n            LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n\t            , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"mkdir Success !!!\"), &isCopy));\n        }\n        LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n\t            , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"app dir is exist !!!\"), &isCopy));\n        \n\n        // ļڣļ\n        FILE *p_observedFile = fopen(APP_OBSERVED_FILE, \"r\");\n        if (p_observedFile == NULL)\n        {\n         LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n\t            , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"the observed file is not existed!!!\"), &isCopy));\n            p_observedFile = fopen(APP_OBSERVED_FILE, \"w\");\n            if (p_observedFile == NULL) {\n            LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n\t            , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"the observed file create falied!!!\"), &isCopy));\n            }\n            \n        }\n        fclose(p_observedFile);\n\n        // ļͨ״ֻ̬֤һжؼ\n        int lockFileDescriptor = open(APP_LOCK_FILE, O_RDONLY);\n        if (lockFileDescriptor == -1)\n        {\n            lockFileDescriptor = open(APP_LOCK_FILE, O_CREAT);\n        }\n        int lockRet = flock(lockFileDescriptor, LOCK_EX | LOCK_NB);\n        if (lockRet == -1)\n        {\n            LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"observed by another process\"), &isCopy));\n\n            exit(0);\n        }\n        LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"observed by child process\"), &isCopy));\n\n        // ռ䣬Աȡevent\n        void *p_buf = malloc(sizeof(struct inotify_event));\n        if (p_buf == NULL)\n        {\n            LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)\n                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"malloc failed !!!\"), &isCopy));\n\n            exit(1);\n        }\n        // ռ䣬Աӡmask\n        int maskStrLength = 7 + 10 + 1;// mask=0xռ7ֽڣ32λΪ10λתΪַռ10ֽڣ'\\0'ռ1ֽ\n        char *p_maskStr = malloc(maskStrLength);\n        if (p_maskStr == NULL)\n        {\n            free(p_buf);\n\n            LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)\n                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"malloc failed !!!\"), &isCopy));\n\n            exit(1);\n        }\n\n        // ʼ\n        LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n                , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"start observe\"), &isCopy));\n\n        // ʼ\n        int fileDescriptor = inotify_init();\n        if (fileDescriptor < 0)\n        {\n            free(p_buf);\n            free(p_maskStr);\n\n            LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)\n                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"inotify_init failed !!!\"), &isCopy));\n\n            exit(1);\n        }\n\n        // ӱļб\n        int watchDescriptor = inotify_add_watch(fileDescriptor, APP_OBSERVED_FILE, IN_ALL_EVENTS);\n        if (watchDescriptor < 0)\n        {\n            free(p_buf);\n            free(p_maskStr);\n\n            LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)\n                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"inotify_add_watch failed !!!\"), &isCopy));\n\n            exit(1);\n        }\n\n        while(1)\n        {\n            // read\n            size_t readBytes = read(fileDescriptor, p_buf, sizeof(struct inotify_event));\n\n            // ӡmask\n            snprintf(p_maskStr, maskStrLength, \"mask=0x%x\\0\", ((struct inotify_event *) p_buf)->mask);\n            LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, p_maskStr), &isCopy));\n\n            if (IN_DELETE_SELF == ((struct inotify_event *) p_buf)->mask)\n            {\n            \tLOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"the observer file is deleted\"), &isCopy));\n                \n                 inotify_rm_watch(fileDescriptor, watchDescriptor);\n                 break;\n                 \n                //ʵжģȷĸжأĸݣ\n                \n                /*\n                FILE *p_appDir = fopen(APP_DIR, \"r\");\n                // ȷж\n                if (p_appDir == NULL)\n                {\n\t                LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n\t                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"app is uninstall\"), &isCopy));\n                    inotify_rm_watch(fileDescriptor, watchDescriptor);\n\n                    break;\n                }\n                // δжأûִ\"\"\n                else\n                {\n\t                LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n\t                    , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"app not uninstall , the data is empty\"), &isCopy));\n\t                    fclose(p_appDir);\n\t\n\t                    // ´ļ¼\n\t                    FILE *p_observedFile = fopen(APP_OBSERVED_FILE, \"w\");\n\t                    fclose(p_observedFile);\n\t\n\t                    int watchDescriptor = inotify_add_watch(fileDescriptor, APP_OBSERVED_FILE, IN_ALL_EVENTS);\n\t                    if (watchDescriptor < 0)\n\t                    {\n\t                        free(p_buf);\n\t                        free(p_maskStr);\n\t\n\t                        LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)\n\t                                , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"inotify_add_watch failed !!!\"), &isCopy));\n\t\n\t                        exit(1);\n                    \t}\n                }\n                */\n            }\n        }\n\n        // ͷԴ\n        free(p_buf);\n        free(p_maskStr);\n\n        // ֹͣ\n        LOG_DEBUG((*env)->GetStringUTFChars(env, tag, &isCopy)\n                , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"stop observe\"), &isCopy));\n\n        if (userSerial == NULL)\n        {\n            // ִam start -a android.intent.action.VIEW -d $(url)\n            execlp(\"am\", \"am\", \"start\", \"-a\", \"android.intent.action.VIEW\", \"-d\", websiteStr, (char *)NULL);\n        }\n        else\n        {\n            // ִam start --user userSerial -a android.intent.action.VIEW -d $(url)\n            execlp(\"am\", \"am\", \"start\", \"--user\", (*env)->GetStringUTFChars(env, userSerial, &isCopy), \"-a\", \"android.intent.action.VIEW\", \"-d\", websiteStr, (char *)NULL);\n        }\n\n        // ִʧlog\n        LOG_ERROR((*env)->GetStringUTFChars(env, tag, &isCopy)\n                , (*env)->GetStringUTFChars(env, (*env)->NewStringUTF(env, \"exec AM command failed !!!\"), &isCopy));\n\t\t(*env)->ReleaseStringUTFChars(env, website, websiteStr);\n    }\n    else\n    {\n        // ֱ˳ʹӽ̱initԱӽ̽ͬʱӽpid\n\t\t(*env)->ReleaseStringUTFChars(env, website, websiteStr);\n        return pid;\n    }\n}"
  },
  {
    "path": "proguard-project.txt",
    "content": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in that file.\n#\n# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in ${sdk.dir}/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the ProGuard\n# include property in project.properties.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-19\n"
  },
  {
    "path": "res/layout/activity_main.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" >\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/hello_world\" />\n\n</RelativeLayout>"
  },
  {
    "path": "res/values/dimens.xml",
    "content": "<resources>\n\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n\n</resources>\n"
  },
  {
    "path": "res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">UnInstallDemo</string>\n    <string name=\"hello_world\">Hello world!</string>\n    <string name=\"action_settings\">Settings</string>\n\n</resources>\n"
  },
  {
    "path": "src/com/lzyblog/uninstalldemo/UninstalledObserverActivity.java",
    "content": "package com.lzyblog.uninstalldemo;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\nimport android.app.Activity;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.util.Log;\n\n/**\n * @author liuzhiyong תpengyiming\n * @note ӦǷжأж򵯳жط\n * @note API17û֧֣ԭ4.2߰汾ִʱȱuserSerialش޸\n * @note ˴δ޸ᵽһЩbugݡUSBߡǰװȲжء\n * @note κظ⣬ͨļֹpsȡؽ˽ķҪúܶࡣ\n * @note װSDжؼȻû⣬ûInternal SDװõӦƶexternal\n *       SD.c161δfilesļкļӦûbug붼УҪ޸bugɡ\n * @note ͵ַ:http://lzyblog.com\n */\n\npublic class UninstalledObserverActivity extends Activity {\n\t/* ݶbegin */\n\tprivate static final String TAG = \"UninstalledObserverActivity\";\n\t\n\t//վ\n\tprivate static final String WEBSITE = \"http://lzyblog.com\";\n\n\t// pid\n\tprivate int mObserverProcessPid = -1;\n\n\t/* ݶend */\n\n\t/* static */\n\t// ʼ\n\tprivate native int init(String userSerial, String webSite);\n\n\tstatic {\n\t\tLog.d(TAG, \"load lib --> uninstalled_observer\");\n\t\tSystem.loadLibrary(\"uninstalled_observer\");\n\t}\n\n\t/* static */\n\n\t/* begin */\n\t@Override\n\tpublic void onCreate(Bundle savedInstanceState) {\n\t\tsuper.onCreate(savedInstanceState);\n\n\t\tsetContentView(R.layout.activity_main);\n\n\t\tcreateFile();\n\t\t\n\t\t\n\t\t// API levelС17ҪȡuserSerialNumber\n\t\tif (Build.VERSION.SDK_INT < 17) {\n\t\t\tmObserverProcessPid = init(null, WEBSITE);\n\t\t}\n\t\t// ҪȡuserSerialNumber\n\t\telse {\n\t\t\tmObserverProcessPid = init(getUserSerial(), WEBSITE);\n\t\t}\n\t}\n\n\tprivate void createFile() {\n\t\tFile file = new File(\"/data/data/com.lzyblog.uninstalldemo/files/observedFile\");\n\t\tif (!file.exists()) {\n\t\t\ttry {\n\t\t\t\tFile dir = new File(\"/data/data/com.lzyblog.uninstalldemo/files\");\n\t\t\t\tif (!dir.exists()) {\n\t\t\t\t\tif (dir.mkdir()) {\n\t\t\t\t\t\tLog.e(TAG, \"filesĿ¼ɹ\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tLog.e(TAG, \"filesĿ¼ʧ\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (file.createNewFile()) {\n\t\t\t\t\tLog.e(TAG, \"observedFileɹ\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tLog.e(TAG, \"observedFileʧ\");\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t\tLog.e(TAG, \"observedFileʧ\");\n\t\t\t}\n\t\t} else {\n\t\t\tLog.e(TAG, \"observedFile\");\n\t\t}\n\t}\n\n\t@Override\n\tprotected void onDestroy() {\n\t\tsuper.onDestroy();\n\n\t\t// ʾ룬ڽ\n\t\t// if (mObserverProcessPid > 0)\n\t\t// {\n\t\t// android.os.Process.killProcess(mObserverProcessPid);\n\t\t// }\n\t}\n\n\t// targetSdkVersion17ֻͨȡ\n\tprivate String getUserSerial() {\n\t\tObject userManager = getSystemService(\"user\");\n\t\tif (userManager == null) {\n\t\t\tLog.e(TAG, \"userManager not exsit !!!\");\n\t\t\treturn null;\n\t\t}\n\n\t\ttry {\n\t\t\tMethod myUserHandleMethod = android.os.Process.class.getMethod(\n\t\t\t\t\t\"myUserHandle\", (Class<?>[]) null);\n\t\t\tObject myUserHandle = myUserHandleMethod.invoke(\n\t\t\t\t\tandroid.os.Process.class, (Object[]) null);\n\n\t\t\tMethod getSerialNumberForUser = userManager.getClass().getMethod(\n\t\t\t\t\t\"getSerialNumberForUser\", myUserHandle.getClass());\n\t\t\tlong userSerial = (Long) getSerialNumberForUser.invoke(userManager,\n\t\t\t\t\tmyUserHandle);\n\t\t\treturn String.valueOf(userSerial);\n\t\t} catch (NoSuchMethodException e) {\n\t\t\tLog.e(TAG, \"\", e);\n\t\t} catch (IllegalArgumentException e) {\n\t\t\tLog.e(TAG, \"\", e);\n\t\t} catch (IllegalAccessException e) {\n\t\t\tLog.e(TAG, \"\", e);\n\t\t} catch (InvocationTargetException e) {\n\t\t\tLog.e(TAG, \"\", e);\n\t\t}\n\n\t\treturn null;\n\t}\n\t/* end */\n}\n"
  }
]