| Index: chrome/android/java/src/org/chromium/chrome/browser/init/AndroidIPCWatcher.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AndroidIPCWatcher.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AndroidIPCWatcher.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f4fde74ed641777e08628cfb68df282985915ab2
|
| --- /dev/null
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AndroidIPCWatcher.java
|
| @@ -0,0 +1,199 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.chrome.browser.init;
|
| +
|
| +import android.annotation.TargetApi;
|
| +import android.content.ContentResolver;
|
| +import android.content.Context;
|
| +import android.content.pm.PackageManager;
|
| +import android.hardware.input.InputManager;
|
| +import android.location.LocationManager;
|
| +import android.net.ConnectivityManager;
|
| +import android.os.Build;
|
| +import android.os.Looper;
|
| +import android.os.SystemClock;
|
| +import android.os.UserManager;
|
| +import android.view.accessibility.AccessibilityManager;
|
| +
|
| +import org.chromium.base.Log;
|
| +
|
| +import java.lang.reflect.Field;
|
| +import java.lang.reflect.InvocationHandler;
|
| +import java.lang.reflect.Method;
|
| +import java.lang.reflect.Proxy;
|
| +import java.util.Arrays;
|
| +
|
| +public class AndroidIPCWatcher {
|
| + private static final Looper sMainLooper = Looper.getMainLooper();
|
| + private static boolean sProxiesInstalled;
|
| + private static final String TAG = "AndroidIPCWatcher";
|
| +
|
| + private static final class IPCListener implements InvocationHandler {
|
| + private final Object mSystemImpl;
|
| +
|
| + public IPCListener(Object systemImpl) {
|
| + mSystemImpl = systemImpl;
|
| + }
|
| +
|
| + @Override
|
| + @TargetApi(Build.VERSION_CODES.KITKAT)
|
| + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
| + long initial = SystemClock.elapsedRealtimeNanos();
|
| + Object returnValue = method.invoke(mSystemImpl, args);
|
| + long after = SystemClock.elapsedRealtimeNanos();
|
| +
|
| + // ignore non-main thread
|
| + if (!sMainLooper.equals(Looper.myLooper())) return returnValue;
|
| +
|
| + if (after - initial > 10e6) {
|
| + Log.e(TAG, mSystemImpl.getClass().getName() + "#" + method.getName() + " took "
|
| + + (after - initial) / 1000 + " us");
|
| + Log.e(TAG, "stack=" + Arrays.toString(Thread.currentThread().getStackTrace()));
|
| + }
|
| + return returnValue;
|
| + }
|
| + }
|
| +
|
| + @SuppressWarnings({"rawtypes", "unchecked" })
|
| + public static void install(Context context) {
|
| + if (sProxiesInstalled) return;
|
| + sProxiesInstalled = true;
|
| +
|
| + // 1. Package Manager
|
| + try {
|
| + PackageManager packageManager = context.getPackageManager();
|
| + Field field = packageManager.getClass().getDeclaredField("mPM");
|
| + field.setAccessible(true);
|
| + Object listener = Proxy.newProxyInstance(context.getClassLoader(), new Class[] {
|
| + Class.forName("android.content.pm.IPackageManager") },
|
| + new IPCListener(field.get(packageManager)));
|
| + field.set(packageManager, listener);
|
| + } catch (Throwable throwable) {
|
| + Log.d(TAG, "Failed to intercept IPackageManager: " + throwable);
|
| + }
|
| +
|
| + // 2. ContentResolver
|
| +
|
| + // Force internal ContentService to get assigned
|
| + ContentResolver.getSyncAdapterTypes();
|
| + try {
|
| + Field field = ContentResolver.class.getDeclaredField("sContentService");
|
| + field.setAccessible(true);
|
| + Object listener = Proxy.newProxyInstance(context.getClassLoader(), new Class[] {
|
| + Class.forName("android.content.IContentService") },
|
| + new IPCListener(field.get(ContentResolver.class)));
|
| + field.set(ContentResolver.class, listener);
|
| + } catch (Throwable throwable) {
|
| + Log.d(TAG, "Failed to intercept IContentService: " + throwable);
|
| + }
|
| +
|
| + // 3. UserManager
|
| + try {
|
| + UserManager manager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
| + Field field = manager.getClass().getDeclaredField("mService");
|
| + field.setAccessible(true);
|
| + Object listener = Proxy.newProxyInstance(context.getClassLoader(), new Class[] {
|
| + Class.forName("android.os.IUserManager") },
|
| + new IPCListener(field.get(manager)));
|
| + field.set(manager, listener);
|
| + } catch (Throwable throwable) {
|
| + Log.d(TAG, "Failed to intercept IUserManager: " + throwable);
|
| + }
|
| +
|
| + // 4. InputManager
|
| + try {
|
| + InputManager manager = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
|
| + Field field = manager.getClass().getDeclaredField("mIm");
|
| + field.setAccessible(true);
|
| + Object listener = Proxy.newProxyInstance(context.getClassLoader(), new Class[] {
|
| + Class.forName("android.hardware.input.IInputManager") },
|
| + new IPCListener(field.get(manager)));
|
| + field.set(manager, listener);
|
| + } catch (Throwable throwable) {
|
| + Log.d(TAG, "Failed to intercept InputManager: " + throwable);
|
| + }
|
| +
|
| + // 5. LocationManager
|
| + try {
|
| + LocationManager manager =
|
| + (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
| + Field field = manager.getClass().getDeclaredField("mService");
|
| + field.setAccessible(true);
|
| + Object listener = Proxy.newProxyInstance(context.getClassLoader(), new Class[] {
|
| + Class.forName("android.location.ILocationManager") },
|
| + new IPCListener(field.get(manager)));
|
| + field.set(manager, listener);
|
| + } catch (Throwable throwable) {
|
| + Log.d(TAG, "Failed to intercept LocationManager: " + throwable);
|
| + }
|
| +
|
| +
|
| + // 6. ActivityManager
|
| + try {
|
| + Class activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
|
| + Method defaultMethod = activityManagerNativeClass.getMethod("getDefault",
|
| + new Class[] {});
|
| + Object iActivityManager = defaultMethod.invoke(activityManagerNativeClass);
|
| + Object listener = Proxy.newProxyInstance(context.getClassLoader(), new Class[] {
|
| + Class.forName("android.app.IActivityManager") },
|
| + new IPCListener(iActivityManager));
|
| +
|
| + Field field = activityManagerNativeClass.getDeclaredField("gDefault");
|
| + field.setAccessible(true);
|
| + Object singleton = field.get(activityManagerNativeClass);
|
| +
|
| + Class singletonClass = Class.forName("android.util.Singleton");
|
| + field = singletonClass.getDeclaredField("mInstance");
|
| + field.setAccessible(true);
|
| + field.set(singleton, listener);
|
| + } catch (Throwable throwable) {
|
| + Log.d(TAG, "Failed to intercept ActivityManager: " + throwable);
|
| + }
|
| +
|
| + // 7. LockSettings
|
| + try {
|
| + android.provider.Settings.Secure.getString(context.getContentResolver(), "foo");
|
| + Class manager = android.provider.Settings.Secure.class;
|
| + Field field = manager.getDeclaredField("sLockSettings");
|
| + field.setAccessible(true);
|
| + Object listener = Proxy.newProxyInstance(context.getClassLoader(), new Class[] {
|
| + Class.forName("com.android.internal.widget.ILockSettings") },
|
| + new IPCListener(field.get(manager)));
|
| + field.set(manager, listener);
|
| + } catch (Throwable throwable) {
|
| + throwable.printStackTrace();
|
| + Log.d(TAG, "Failed to intercept LockManager: " + throwable);
|
| + }
|
| +
|
| + // 8. AccessibilityManager
|
| + try {
|
| + AccessibilityManager manager =
|
| + (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
|
| + Field field = manager.getClass().getDeclaredField("mService");
|
| + field.setAccessible(true);
|
| + Object listener = Proxy.newProxyInstance(context.getClassLoader(), new Class[] {
|
| + Class.forName("android.view.accessibility.IAccessibilityManager") },
|
| + new IPCListener(field.get(manager)));
|
| + field.set(manager, listener);
|
| + } catch (Throwable throwable) {
|
| + Log.d(TAG, "Failed to intercept AccessibilityManager: " + throwable);
|
| + }
|
| + // 9. ConnectivityManager
|
| + try {
|
| + ConnectivityManager manager =
|
| + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
| + Field field = manager.getClass().getDeclaredField("mService");
|
| + field.setAccessible(true);
|
| + Object listener = Proxy.newProxyInstance(context.getClassLoader(), new Class[] {
|
| + Class.forName("android.net.IConnectivityManager") },
|
| + new IPCListener(field.get(manager)));
|
| + field.set(manager, listener);
|
| + } catch (Throwable throwable) {
|
| + Log.d(TAG, "Failed to intercept ConnectivityManager: " + throwable);
|
| + }
|
| +
|
| +
|
| + }
|
| +}
|
|
|