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