AppDirObserver主要负责监控相应目录下面apk的变动
我们以监视/system/app的代码为例
mSystemInstallObserver = newAppDirObserver(mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
mSystemInstallObserver.startWatching();
首先看一下这几个类的关系:
主要的监控工作是通过ObserverThread来实现的,而ObserverThread又是通过JNI调用C层的代码来控制的。
AppDirObserver继承自FileObserver,而FileObserver有一个ObserverThread类型的变量s_observerThread
FileObserver内有一段这样的初始化代码
static { s_observerThread = new ObserverThread(); s_observerThread.start(); } public ObserverThread() { super("FileObserver"); m_fd = init(); }
这里调用native函数init并返回一个句柄m_fd
对应的jni实现在android_util_FileObserver.cppstatic jint android_os_fileobserver_init(JNIEnv* env, jobject object) { #ifdef HAVE_INOTIFY return (jint)inotify_init(); #else // HAVE_INOTIFY return -1; #endif // HAVE_INOTIFY }
只是简单的调用inotify_init,从 Linux 2.6.13 内核开始,Linux 就推出了 inotify,允许监控程序打开一个独立文件描述符,并针对事件集监控一个或者多个文件,例如打开、关闭、移动/重命名、删除、创建或者改变属性
inotify_init用于创建一个 inotify 实例的系统调用,并返回一个指向该实例的文件描述符。
回到static部分,接着调用s_observerThread.start,进入run
public void run() { observe(m_fd); }
Observe也是一个native函数,这里的参数m_fd是前面init返回的
static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd) { #ifdef HAVE_INOTIFY char event_buf[512]; struct inotify_event* event; while (1) { int event_pos = 0; int num_bytes = read(fd, event_buf, sizeof(event_buf)); if (num_bytes < (int)sizeof(*event)) { if (errno == EINTR) continue; ALOGE("***** ERROR! android_os_fileobserver_observe() got a short event!"); return; } while (num_bytes >= (int)sizeof(*event)) { int event_size; event = (struct inotify_event *)(event_buf + event_pos); jstring path = NULL; if (event->len > 0) { path = env->NewStringUTF(event->name); } env->CallVoidMethod(object, method_onEvent, event->wd, event->mask, path); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); } if (path != NULL) { env->DeleteLocalRef(path); } event_size = sizeof(*event) + event->len; num_bytes -= event_size; event_pos += event_size; } } #endif // HAVE_INOTIFY }
这里读取fd上是否有事件发生,如果有则调用Java层的onEvent函数
了解了这么多,我们回到
mSystemInstallObserver = new AppDirObserver(mSystemAppDir.getPath(), OBSERVER_EVENTS, true); mSystemInstallObserver.startWatching();
这里
private static final int OBSERVER_EVENTS =REMOVE_EVENTS | ADD_EVENTS;
表示只监听文件添加和删除事件
当我们调用startWatching时
*/ public void startWatching() { if (m_descriptor < 0) { m_descriptor = s_observerThread.startWatching(m_path, m_mask, this); } }
调用ObserverThread的startWatching
public int startWatching(String path, int mask, FileObserver observer) { int wfd = startWatching(m_fd, path, mask); Integer i = new Integer(wfd); if (wfd >= 0) { synchronized (m_observers) { m_observers.put(i, new WeakReference(observer)); } } return i; }
调用native 函数startWatching并添加到m_observers
static jint android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd, jstring pathString, jint mask) { int res = -1; #ifdef HAVE_INOTIFY if (fd >= 0) { const char* path = env->GetStringUTFChars(pathString, NULL); res = inotify_add_watch(fd, path, mask); env->ReleaseStringUTFChars(pathString, path); } #endif // HAVE_INOTIFY return res; }
inotify_add_watch
增加对文件或者目录的监控,并指定需要监控哪些事件。标志用于控制是否将事件添加到已有的监控中,是否只有路径代表一个目录才进行监控,是否要追踪符号链接,是否进行一次性监控,当首次事件出现后就停止监控。
当有事件到来时,调用java层的onEvent,在AppDirObserver中实现
public void onEvent(int event, String path) { String removedPackage = null; int removedAppId = -1; int[] removedUsers = null; String addedPackage = null; int addedAppId = -1; int[] addedUsers = null; // TODO post a message to the handler to obtain serial ordering synchronized (mInstallLock) { String fullPathStr = null; File fullPath = null; if (path != null) { fullPath = new File(mRootDir, path); fullPathStr = fullPath.getPath(); } if (DEBUG_APP_DIR_OBSERVER) Log.v(TAG, "File " + fullPathStr + " changed: " + Integer.toHexString(event)); if (!isPackageFilename(path)) { if (DEBUG_APP_DIR_OBSERVER) Log.v(TAG, "Ignoring change of non-package file: " + fullPathStr); return; } // Ignore packages that are being installed or // have just been installed. if (ignoreCodePath(fullPathStr)) { return; } PackageParser.Package p = null; PackageSetting ps = null; // reader synchronized (mPackages) { p = mAppDirs.get(fullPathStr); if (p != null) { ps = mSettings.mPackages.get(p.applicationInfo.packageName); if (ps != null) { removedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); } else { removedUsers = sUserManager.getUserIds(); } } addedUsers = sUserManager.getUserIds(); } if ((event&REMOVE_EVENTS) != 0) { if (ps != null) { removePackageLI(ps, true); removedPackage = ps.name; removedAppId = ps.appId; } } if ((event&ADD_EVENTS) != 0) { if (p == null) { p = scanPackageLI(fullPath, (mIsRom ? PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR: 0) | PackageParser.PARSE_CHATTY | PackageParser.PARSE_MUST_BE_APK, SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME, System.currentTimeMillis(), UserHandle.ALL); if (p != null) { /* * TODO this seems dangerous as the package may have * changed since we last acquired the mPackages * lock. */ // writer synchronized (mPackages) { updatePermissionsLPw(p.packageName, p, p.permissions.size() > 0 ? UPDATE_PERMISSIONS_ALL : 0); } addedPackage = p.applicationInfo.packageName; addedAppId = UserHandle.getAppId(p.applicationInfo.uid); } } } // reader synchronized (mPackages) { mSettings.writeLPr(); } } if (removedPackage != null) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, removedAppId); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false); sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras, null, null, removedUsers); } if (addedPackage != null) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, addedAppId); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, extras, null, null, addedUsers); } }
从代码中可以看出,如果是添加事件,则调用scanPackageLI,并使用updatePermissionsLPw授权;如果是删除事件则调用removePackageLI移除该apk的相关信息。最后都要调用writeLPr重新保存相关信息到packages.xml