Showing preview only (1,707K chars total). Download the full file or copy to clipboard to get everything.
Repository: DroidPluginTeam/DroidPlugin
Branch: master
Commit: c6ebf652e0f7
Files: 270
Total size: 1.6 MB
Directory structure:
gitextract_kra60iuy/
├── .gitignore
├── DOC/
│ ├── .gitignore
│ ├── hejunlin/
│ │ ├── LICENSE
│ │ ├── 插件占坑,四大组件动态注册前奏(一) 系统Activity的启动流程.md
│ │ ├── 插件占坑,四大组件动态注册前奏(三) 系统BroadCast的注册发送流程.md
│ │ ├── 插件占坑,四大组件动态注册前奏(二) 系统Service的启动流程.md
│ │ ├── 插件开发之360 DroidPlugin源码分析(一)初识.md
│ │ ├── 插件开发之360 DroidPlugin源码分析(三)Binder代理.md
│ │ ├── 插件开发之360 DroidPlugin源码分析(二)Hook机制.md
│ │ ├── 插件开发之360 DroidPlugin源码分析(五)Service预注册占坑.md
│ │ └── 插件开发之360 DroidPlugin源码分析(四)Activity预注册占坑.md
│ ├── tianweishu/
│ │ ├── .gitignore
│ │ ├── Activity生命周期管理.md
│ │ ├── BroadcastReceiver插件化.md
│ │ ├── ClassLoader管理.md
│ │ ├── ContentProvider插件化.md
│ │ ├── Hook机制之AMS&PMS.md
│ │ ├── Hook机制之Binder-Hook.md
│ │ ├── Hook机制之代理Hook.md
│ │ ├── Service插件化.md
│ │ └── 概述.md
│ └── 插件机制介绍.pptx
├── LICENSE
├── project/
│ ├── .gitignore
│ ├── Libraries/
│ │ └── DroidPlugin/
│ │ ├── LICENSE.txt
│ │ ├── build.gradle
│ │ ├── lib/
│ │ │ └── layoutlib.jar
│ │ ├── proguard-project.txt
│ │ ├── project.properties
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── aidl/
│ │ │ ├── android/
│ │ │ │ └── app/
│ │ │ │ └── IServiceConnection.aidl
│ │ │ └── com/
│ │ │ └── morgoo/
│ │ │ └── droidplugin/
│ │ │ └── pm/
│ │ │ ├── IApplicationCallback.aidl
│ │ │ ├── IPackageDataObserver.aidl
│ │ │ └── IPluginManager.aidl
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── morgoo/
│ │ │ ├── droidplugin/
│ │ │ │ ├── MyCrashHandler.java
│ │ │ │ ├── PluginApplication.java
│ │ │ │ ├── PluginHelper.java
│ │ │ │ ├── PluginManagerService.java
│ │ │ │ ├── PluginPatchManager.java
│ │ │ │ ├── PluginServiceProvider.java
│ │ │ │ ├── am/
│ │ │ │ │ ├── BaseActivityManagerService.java
│ │ │ │ │ ├── MyActivityManagerService.java
│ │ │ │ │ ├── RunningActivities.java
│ │ │ │ │ ├── RunningProcessList.java
│ │ │ │ │ ├── ServiceStubMap.java
│ │ │ │ │ └── StaticProcessList.java
│ │ │ │ ├── core/
│ │ │ │ │ ├── Env.java
│ │ │ │ │ ├── PluginClassLoader.java
│ │ │ │ │ ├── PluginDirHelper.java
│ │ │ │ │ └── PluginProcessManager.java
│ │ │ │ ├── hook/
│ │ │ │ │ ├── BaseHookHandle.java
│ │ │ │ │ ├── Hook.java
│ │ │ │ │ ├── HookFactory.java
│ │ │ │ │ ├── HookedMethodHandler.java
│ │ │ │ │ ├── binder/
│ │ │ │ │ │ ├── BinderHook.java
│ │ │ │ │ │ ├── IAppOpsServiceBinderHook.java
│ │ │ │ │ │ ├── IAudioServiceBinderHook.java
│ │ │ │ │ │ ├── IClipboardBinderHook.java
│ │ │ │ │ │ ├── IContentServiceBinderHook.java
│ │ │ │ │ │ ├── IDisplayManagerBinderHook.java
│ │ │ │ │ │ ├── IGraphicsStatsBinderHook.java
│ │ │ │ │ │ ├── IInputMethodManagerBinderHook.java
│ │ │ │ │ │ ├── ILocationManagerBinderHook.java
│ │ │ │ │ │ ├── IMediaRouterServiceBinderHook.java
│ │ │ │ │ │ ├── IMmsBinderHook.java
│ │ │ │ │ │ ├── IMountServiceBinderHook.java
│ │ │ │ │ │ ├── INotificationManagerBinderHook.java
│ │ │ │ │ │ ├── IPhoneSubInfoBinderHook.java
│ │ │ │ │ │ ├── ISearchManagerBinderHook.java
│ │ │ │ │ │ ├── ISessionManagerBinderHook.java
│ │ │ │ │ │ ├── ISmsBinderHook.java
│ │ │ │ │ │ ├── ISubBinderHook.java
│ │ │ │ │ │ ├── ITelephonyBinderHook.java
│ │ │ │ │ │ ├── ITelephonyRegistryBinderHook.java
│ │ │ │ │ │ ├── IWifiManagerBinderHook.java
│ │ │ │ │ │ ├── IWindowManagerBinderHook.java
│ │ │ │ │ │ ├── MyServiceManager.java
│ │ │ │ │ │ ├── ServiceManagerBinderHook.java
│ │ │ │ │ │ └── ServiceManagerCacheBinderHook.java
│ │ │ │ │ ├── handle/
│ │ │ │ │ │ ├── IActivityManagerHookHandle.java
│ │ │ │ │ │ ├── IAppOpsServiceHookHandle.java
│ │ │ │ │ │ ├── IAudioServiceHookHandle.java
│ │ │ │ │ │ ├── IClipboardHookHandle.java
│ │ │ │ │ │ ├── IContentProviderInvokeHandle.java
│ │ │ │ │ │ ├── IContentServiceHandle.java
│ │ │ │ │ │ ├── IDisplayManagerHookHandle.java
│ │ │ │ │ │ ├── IGraphicsStatsHookHandle.java
│ │ │ │ │ │ ├── IInputMethodManagerHookHandle.java
│ │ │ │ │ │ ├── ILocationManagerHookHandle.java
│ │ │ │ │ │ ├── IMediaRouterServiceHookHandle.java
│ │ │ │ │ │ ├── IMmsHookHandle.java
│ │ │ │ │ │ ├── IMountServiceHookHandle.java
│ │ │ │ │ │ ├── INotificationManagerHookHandle.java
│ │ │ │ │ │ ├── IPackageManagerHookHandle.java
│ │ │ │ │ │ ├── IPhoneSubInfoHookHandle.java
│ │ │ │ │ │ ├── ISearchManagerHookHandle.java
│ │ │ │ │ │ ├── ISessionManagerHookHandle.java
│ │ │ │ │ │ ├── ISmsHookHandle.java
│ │ │ │ │ │ ├── ISubBinderHookHandle.java
│ │ │ │ │ │ ├── ITelephonyHookHandle.java
│ │ │ │ │ │ ├── ITelephonyRegistryHookHandle.java
│ │ │ │ │ │ ├── IWifiManagerHookHandle.java
│ │ │ │ │ │ ├── IWindowManagerHookHandle.java
│ │ │ │ │ │ ├── IWindowSessionInvokeHandle.java
│ │ │ │ │ │ ├── LibCoreHookHandle.java
│ │ │ │ │ │ ├── PluginCallback.java
│ │ │ │ │ │ ├── PluginInstrumentation.java
│ │ │ │ │ │ ├── ReplaceCallingPackageHookedMethodHandler.java
│ │ │ │ │ │ └── WebViewFactoryProviderHookHandle.java
│ │ │ │ │ ├── proxy/
│ │ │ │ │ │ ├── IActivityManagerHook.java
│ │ │ │ │ │ ├── IContentProviderHook.java
│ │ │ │ │ │ ├── IPackageManagerHook.java
│ │ │ │ │ │ ├── IWindowSessionHook.java
│ │ │ │ │ │ ├── InstrumentationHook.java
│ │ │ │ │ │ ├── LibCoreHook.java
│ │ │ │ │ │ ├── PluginCallbackHook.java
│ │ │ │ │ │ ├── ProxyHook.java
│ │ │ │ │ │ └── WebViewFactoryProviderHook.java
│ │ │ │ │ └── xhook/
│ │ │ │ │ └── SQLiteDatabaseHook.java
│ │ │ │ ├── pm/
│ │ │ │ │ ├── IPluginManagerImpl.java
│ │ │ │ │ ├── PluginManager.java
│ │ │ │ │ └── parser/
│ │ │ │ │ ├── IntentMatcher.java
│ │ │ │ │ ├── PackageParser.java
│ │ │ │ │ ├── PackageParserApi15.java
│ │ │ │ │ ├── PackageParserApi16.java
│ │ │ │ │ ├── PackageParserApi20.java
│ │ │ │ │ ├── PackageParserApi21.java
│ │ │ │ │ ├── PackageParserApi22.java
│ │ │ │ │ ├── PackageParserApi22Preview1.java
│ │ │ │ │ └── PluginPackageParser.java
│ │ │ │ ├── reflect/
│ │ │ │ │ ├── FieldUtils.java
│ │ │ │ │ ├── MemberUtils.java
│ │ │ │ │ ├── MethodUtils.java
│ │ │ │ │ ├── Utils.java
│ │ │ │ │ └── Validate.java
│ │ │ │ └── stub/
│ │ │ │ ├── AbstractContentProviderStub.java
│ │ │ │ ├── AbstractServiceStub.java
│ │ │ │ ├── ActivityStub.java
│ │ │ │ ├── ContentProviderStub.java
│ │ │ │ ├── MyFakeIBinder.java
│ │ │ │ ├── ServcesManager.java
│ │ │ │ ├── ServiceStub.java
│ │ │ │ └── ShortcutProxyActivity.java
│ │ │ └── helper/
│ │ │ ├── AttributeCache.java
│ │ │ ├── ComponentNameComparator.java
│ │ │ ├── Log.java
│ │ │ ├── MyProxy.java
│ │ │ ├── Utils.java
│ │ │ ├── compat/
│ │ │ │ ├── ActivityManagerCompat.java
│ │ │ │ ├── ActivityManagerNativeCompat.java
│ │ │ │ ├── ActivityThreadCompat.java
│ │ │ │ ├── BuildCompat.java
│ │ │ │ ├── BundleCompat.java
│ │ │ │ ├── CompatibilityInfoCompat.java
│ │ │ │ ├── ContentProviderCompat.java
│ │ │ │ ├── ContentProviderHolderCompat.java
│ │ │ │ ├── IActivityManagerCompat.java
│ │ │ │ ├── IAppOpsServiceCompat.java
│ │ │ │ ├── IAudioServiceCompat.java
│ │ │ │ ├── IClipboardCompat.java
│ │ │ │ ├── IContentServiceCompat.java
│ │ │ │ ├── IDisplayManagerCompat.java
│ │ │ │ ├── IGraphicsStatsCompat.java
│ │ │ │ ├── IInputMethodManagerCompat.java
│ │ │ │ ├── ILocationManagerCompat.java
│ │ │ │ ├── IMediaRouterServiceCompat.java
│ │ │ │ ├── IMmsCompat.java
│ │ │ │ ├── IMountServiceCompat.java
│ │ │ │ ├── INotificationManagerCompat.java
│ │ │ │ ├── IPackageDataObserverCompat.java
│ │ │ │ ├── IPhoneSubInfoCompat.java
│ │ │ │ ├── ISearchManagerCompat.java
│ │ │ │ ├── ISessionManagerCompat.java
│ │ │ │ ├── ISmsCompat.java
│ │ │ │ ├── ISubCompat.java
│ │ │ │ ├── ITelephonyCompat.java
│ │ │ │ ├── ITelephonyRegistryCompat.java
│ │ │ │ ├── IWifiManagerCompat.java
│ │ │ │ ├── IWindowManagerCompat.java
│ │ │ │ ├── NativeLibraryHelperCompat.java
│ │ │ │ ├── PackageManagerCompat.java
│ │ │ │ ├── ParceledListSliceCompat.java
│ │ │ │ ├── ProcessCompat.java
│ │ │ │ ├── QueuedWorkCompat.java
│ │ │ │ ├── ServiceManagerCompat.java
│ │ │ │ ├── SingletonCompat.java
│ │ │ │ ├── SystemPropertiesCompat.java
│ │ │ │ ├── UserHandleCompat.java
│ │ │ │ ├── VMRuntimeCompat.java
│ │ │ │ └── WebViewFactoryCompat.java
│ │ │ └── utils/
│ │ │ └── ProcessUtils.java
│ │ └── res/
│ │ ├── drawable-xxhdpi/
│ │ │ └── plugin_activity_loading.xml
│ │ ├── values/
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── values-v11/
│ │ │ └── styles.xml
│ │ └── values-v14/
│ │ └── styles.xml
│ ├── Test/
│ │ └── ApiTest/
│ │ ├── build.gradle
│ │ ├── lib/
│ │ │ └── dalviksystem.jar
│ │ ├── proguard-project.txt
│ │ ├── project.properties
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── cpp/
│ │ │ ├── Core.cpp
│ │ │ ├── HelperJni/
│ │ │ │ ├── HelperJni.cpp
│ │ │ │ └── HelperJni.h
│ │ │ └── help/
│ │ │ ├── log.h
│ │ │ └── nativehelper/
│ │ │ ├── JNIHelp.cpp
│ │ │ └── JNIHelp.h
│ │ ├── java/
│ │ │ └── com/
│ │ │ ├── example/
│ │ │ │ └── ApiTest/
│ │ │ │ ├── ActivityTestActivity.java
│ │ │ │ ├── BaseService.java
│ │ │ │ ├── Binder1.aidl
│ │ │ │ ├── Binder2.aidl
│ │ │ │ ├── BroadcastReceiverTest.java
│ │ │ │ ├── ContentProviderTest.java
│ │ │ │ ├── ContentProviderTest2.java
│ │ │ │ ├── LaunchModeTestActivity.java
│ │ │ │ ├── MyActivity.java
│ │ │ │ ├── MyContentProvider1.java
│ │ │ │ ├── MyContentProvider2.java
│ │ │ │ ├── NativeTestActivity.java
│ │ │ │ ├── NotificationTest.java
│ │ │ │ ├── Service1.java
│ │ │ │ ├── Service2.java
│ │ │ │ ├── Service3.java
│ │ │ │ ├── Service4.java
│ │ │ │ ├── ServiceTest1.java
│ │ │ │ ├── ServiceTest2.java
│ │ │ │ ├── SingleInstanceActivity.java
│ │ │ │ ├── SingleTaskActivity.java
│ │ │ │ ├── SingleTopActivity.java
│ │ │ │ ├── StandardActivity.java
│ │ │ │ ├── StaticBroadcastReceiver.java
│ │ │ │ └── WebViewTestActivity.java
│ │ │ └── morgoo/
│ │ │ └── nativec/
│ │ │ └── NativeCHelper.java
│ │ └── res/
│ │ ├── layout/
│ │ │ ├── activity_activity_test.xml
│ │ │ ├── activity_launchmode.xml
│ │ │ ├── activity_native_test.xml
│ │ │ ├── activity_web_view_test.xml
│ │ │ ├── broadcast_receiver.xml
│ │ │ ├── content_provider.xml
│ │ │ ├── main.xml
│ │ │ ├── notification_test.xml
│ │ │ └── service.xml
│ │ ├── values/
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── values-v11/
│ │ │ └── styles.xml
│ │ ├── values-v14/
│ │ │ └── styles.xml
│ │ └── values-w820dp/
│ │ └── dimens.xml
│ ├── TestPlugin/
│ │ ├── build.gradle
│ │ ├── proguard-project.txt
│ │ ├── project.properties
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── TestPlugin/
│ │ │ ├── ApkFragment.java
│ │ │ ├── ApkItem.java
│ │ │ ├── InstalledFragment.java
│ │ │ ├── MainActivity.java
│ │ │ └── MyActivity.java
│ │ └── res/
│ │ ├── layout/
│ │ │ ├── apk_item.xml
│ │ │ └── main.xml
│ │ ├── values/
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── values-v11/
│ │ │ └── styles.xml
│ │ └── values-v14/
│ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── readme.md
└── readme_cn.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/project/Libraries/DroidPlugin/gen
/project/Libraries/DroidPlugin/bin
/project/Test/ApiTest/gen
/project/Test/ApiTest/bin
/project/TestPlugin/gen
/project/TestPlugin/bin
/project/gradle
/project/.gradle
/project/.idea
/project/build
/project/local.properties
/happy_chinese_new_year_of_monkey
*.iml
================================================
FILE: DOC/.gitignore
================================================
.DS_Store
================================================
FILE: DOC/hejunlin/LICENSE
================================================
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
================================================
FILE: DOC/hejunlin/插件占坑,四大组件动态注册前奏(一) 系统Activity的启动流程.md
================================================
前言:为什么要了解系统Activity,Service,,BroadCastReceiver,ContentProvider的启动流程,这是一个对于即将理解插件中的四大组件动态注册,占坑的前提,如果不了解的话,那么很难了解插件hook哪些东西,又是如何骗过AMS来启动Activity,Service,BroadCastReceiver,ContentProvider?
本节主要记录系统Activity的启动流程:
先看下时序图:


//接上面两张图:

和插件相关主要在第三张图,
先看H类:这是ActivityThread中的内部类,此类继承自Handler,重写handleMeaage方法, 将msg转换成一个ActivityClientRecord对象,调用ActivityThread类成员函数getPackageInfoNoCheck来获得一个LoadApk对象,并且保存在ActivityClientRecord对象r的成员变量packageInfo中。
ActivityThread有一个该类型的成员变量mH。scheduleLaunchActivity()里会发送一个LAUNCH_ACTIVITY类型的消息,该消息被mH处理并调用handleLaunchActivity()。
handleLaunchActivity(r,main)来启动ActivityClientRecord对象t所描述的一个Activity组件。即MyActivity
```
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int STOP_ACTIVITY_HIDE = 104;
public static final int SHOW_WINDOW = 105;
public static final int HIDE_WINDOW = 106;
public static final int RESUME_ACTIVITY = 107;
public static final int SEND_RESULT = 108;
public static final int DESTROY_ACTIVITY = 109;
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
public static final int NEW_INTENT = 112;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public static final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;
public static final int REQUEST_THUMBNAIL = 117;
public static final int CONFIGURATION_CHANGED = 118;
public static final int CLEAN_UP_CONTEXT = 119;
public static final int GC_WHEN_IDLE = 120;
public static final int BIND_SERVICE = 121;
public static final int UNBIND_SERVICE = 122;
public static final int DUMP_SERVICE = 123;
public static final int LOW_MEMORY = 124;
public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
public static final int RELAUNCH_ACTIVITY = 126;
public static final int PROFILER_CONTROL = 127;
public static final int CREATE_BACKUP_AGENT = 128;
public static final int DESTROY_BACKUP_AGENT = 129;
public static final int SUICIDE = 130;
public static final int REMOVE_PROVIDER = 131;
public static final int ENABLE_JIT = 132;
public static final int DISPATCH_PACKAGE_BROADCAST = 133;
public static final int SCHEDULE_CRASH = 134;
public static final int DUMP_HEAP = 135;
public static final int DUMP_ACTIVITY = 136;
public static final int SLEEPING = 137;
public static final int SET_CORE_SETTINGS = 138;
public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
public static final int TRIM_MEMORY = 140;
public static final int DUMP_PROVIDER = 141;
public static final int UNSTABLE_PROVIDER_DIED = 142;
public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
public static final int INSTALL_PROVIDER = 145;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY";
case PAUSE_ACTIVITY: return "PAUSE_ACTIVITY";
case PAUSE_ACTIVITY_FINISHING: return "PAUSE_ACTIVITY_FINISHING";
case STOP_ACTIVITY_SHOW: return "STOP_ACTIVITY_SHOW";
case STOP_ACTIVITY_HIDE: return "STOP_ACTIVITY_HIDE";
case SHOW_WINDOW: return "SHOW_WINDOW";
case HIDE_WINDOW: return "HIDE_WINDOW";
case RESUME_ACTIVITY: return "RESUME_ACTIVITY";
case SEND_RESULT: return "SEND_RESULT";
case DESTROY_ACTIVITY: return "DESTROY_ACTIVITY";
case BIND_APPLICATION: return "BIND_APPLICATION";
case EXIT_APPLICATION: return "EXIT_APPLICATION";
case NEW_INTENT: return "NEW_INTENT";
case RECEIVER: return "RECEIVER";
case CREATE_SERVICE: return "CREATE_SERVICE";
case SERVICE_ARGS: return "SERVICE_ARGS";
case STOP_SERVICE: return "STOP_SERVICE";
case REQUEST_THUMBNAIL: return "REQUEST_THUMBNAIL";
case CONFIGURATION_CHANGED: return "CONFIGURATION_CHANGED";
case CLEAN_UP_CONTEXT: return "CLEAN_UP_CONTEXT";
case GC_WHEN_IDLE: return "GC_WHEN_IDLE";
case BIND_SERVICE: return "BIND_SERVICE";
case UNBIND_SERVICE: return "UNBIND_SERVICE";
case DUMP_SERVICE: return "DUMP_SERVICE";
case LOW_MEMORY: return "LOW_MEMORY";
case ACTIVITY_CONFIGURATION_CHANGED: return "ACTIVITY_CONFIGURATION_CHANGED";
case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
case PROFILER_CONTROL: return "PROFILER_CONTROL";
case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT";
case SUICIDE: return "SUICIDE";
case REMOVE_PROVIDER: return "REMOVE_PROVIDER";
case ENABLE_JIT: return "ENABLE_JIT";
case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST";
case SCHEDULE_CRASH: return "SCHEDULE_CRASH";
case DUMP_HEAP: return "DUMP_HEAP";
case DUMP_ACTIVITY: return "DUMP_ACTIVITY";
case SLEEPING: return "SLEEPING";
case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
case TRIM_MEMORY: return "TRIM_MEMORY";
case DUMP_PROVIDER: return "DUMP_PROVIDER";
case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED";
case REQUEST_ASSIST_CONTEXT_EXTRAS: return "REQUEST_ASSIST_CONTEXT_EXTRAS";
case TRANSLUCENT_CONVERSION_COMPLETE: return "TRANSLUCENT_CONVERSION_COMPLETE";
case INSTALL_PROVIDER: return "INSTALL_PROVIDER";
}
}
return Integer.toString(code);
}
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case RELAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case PAUSE_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case PAUSE_ACTIVITY_FINISHING:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case STOP_ACTIVITY_SHOW:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
handleStopActivity((IBinder)msg.obj, true, msg.arg2);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case STOP_ACTIVITY_HIDE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
handleStopActivity((IBinder)msg.obj, false, msg.arg2);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SHOW_WINDOW:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityShowWindow");
handleWindowVisibility((IBinder)msg.obj, true);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case HIDE_WINDOW:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityHideWindow");
handleWindowVisibility((IBinder)msg.obj, false);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case RESUME_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
handleResumeActivity((IBinder)msg.obj, true,
msg.arg1 != 0, true);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SEND_RESULT:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult");
handleSendResult((ResultData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case DESTROY_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,
msg.arg2, false);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case EXIT_APPLICATION:
if (mInitialApplication != null) {
mInitialApplication.onTerminate();
}
Looper.myLooper().quit();
break;
case NEW_INTENT:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent");
handleNewIntent((NewIntentData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case RECEIVER:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
handleReceiver((ReceiverData)msg.obj);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case UNBIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind");
handleUnbindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SERVICE_ARGS:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart");
handleServiceArgs((ServiceArgsData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case STOP_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop");
handleStopService((IBinder)msg.obj);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case REQUEST_THUMBNAIL:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "requestThumbnail");
handleRequestThumbnail((IBinder)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case CONFIGURATION_CHANGED:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;
handleConfigurationChanged((Configuration)msg.obj, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case CLEAN_UP_CONTEXT:
ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
cci.context.performFinalCleanup(cci.who, cci.what);
break;
case GC_WHEN_IDLE:
scheduleGcIdler();
break;
case DUMP_SERVICE:
handleDumpService((DumpComponentInfo)msg.obj);
break;
case LOW_MEMORY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "lowMemory");
handleLowMemory();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case ACTIVITY_CONFIGURATION_CHANGED:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
handleActivityConfigurationChanged((IBinder)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case PROFILER_CONTROL:
handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj, msg.arg2);
break;
case CREATE_BACKUP_AGENT:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backupCreateAgent");
handleCreateBackupAgent((CreateBackupAgentData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case DESTROY_BACKUP_AGENT:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backupDestroyAgent");
handleDestroyBackupAgent((CreateBackupAgentData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SUICIDE:
Process.killProcess(Process.myPid());
break;
case REMOVE_PROVIDER:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "providerRemove");
completeRemoveProvider((ProviderRefCount)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case ENABLE_JIT:
ensureJitEnabled();
break;
case DISPATCH_PACKAGE_BROADCAST:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastPackage");
handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SCHEDULE_CRASH:
throw new RemoteServiceException((String)msg.obj);
case DUMP_HEAP:
handleDumpHeap(msg.arg1 != 0, (DumpHeapData)msg.obj);
break;
case DUMP_ACTIVITY:
handleDumpActivity((DumpComponentInfo)msg.obj);
break;
case DUMP_PROVIDER:
handleDumpProvider((DumpComponentInfo)msg.obj);
break;
case SLEEPING:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "sleeping");
handleSleeping((IBinder)msg.obj, msg.arg1 != 0);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SET_CORE_SETTINGS:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setCoreSettings");
handleSetCoreSettings((Bundle) msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case UPDATE_PACKAGE_COMPATIBILITY_INFO:
handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj);
break;
case TRIM_MEMORY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory");
handleTrimMemory(msg.arg1);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case UNSTABLE_PROVIDER_DIED:
handleUnstableProviderDied((IBinder)msg.obj, false);
break;
case REQUEST_ASSIST_CONTEXT_EXTRAS:
handleRequestAssistContextExtras((RequestAssistContextExtras)msg.obj);
break;
case TRANSLUCENT_CONVERSION_COMPLETE:
handleTranslucentConversionComplete((IBinder)msg.obj, msg.arg1 == 1);
break;
case INSTALL_PROVIDER:
handleInstallProvider((ProviderInfo) msg.obj);
break;
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
```
再看handlePeformLanchActivity方法, 发送一个已中止状态的进程间通信请求给ActivityThread.

以MyActivity继承为例(假定是我们app的第一个Activity),MyActivity被启动,共要经历5个大的步骤:
MyActivity组件是由Launcher组件来启动的,而Launcher组件又是Activity管理服务ActivityManagerService来启动的。
MyActivity组件、Launcher组件和ActivityManagerService组件分别运行在不同的进程中,MyActivity启动过程就涉及了
三个进程,这三个进程通过Binder进程间通信来完成。
Launcher组件启动MyActivity的过程如下:
- **Lanuncher组件向ActivityManagerService发送一个启动MyActivity组件的进程间通信请求**
- **ActivityManagerService首先将要启动的MyActivity组件的信息保存下来,然后再向Launcher组件发送一个中止状态的进程间通信请求**
- **Launcher组件进入到中止状态后,就会向ActivityManagerService发送一个已中止状态的进程间通信请求,以便ActivityManagerService可以继续执行MyActivity组件的操作**
- **ActivityManagerService发现用来运行MyActivity组件的应用程序不存在,因此,它就会启动一个新的应用程序进程**
- **新的应用程序进程启动完成后,就会向ActivityManagerService发送一个启动完成的进程间通信请求,以便ActivityManagerService可以继续执行启动MyActivity组件的操作。**
- **ActivityManagerService将第2步保存下来的MyActivity组件的信息发送给第4步创建的应用程序进程,以便它可以将yActivity组件启动起来。**
================================================
FILE: DOC/hejunlin/插件占坑,四大组件动态注册前奏(三) 系统BroadCast的注册发送流程.md
================================================
前言:为什么要了解系统Activity,Service,BroadCastReceiver,ContentProvider的启动流程,这是一个对于即将理解插件中的四大组件动态注册,占坑的前提,如果不了解的话,那么很难了解插件hook哪些东西,又是如何骗过AMS来启动Activity,Service,BroadCastReceiver,ContentProvider?
本节主要记录系统BroadCastReceiver的注册,发送流程:
在了解注册,发送之前,先想一个问题:为什么有广播?
- **1、广播是一种组件之间传递的方式,这些组件可以运行在同一进程中,也可以运行在不同的进程中。**
- **2、广播的机制是建立在Binder进程间通信基础上的。在Binder进程间通信,Client组件在和Service组件进行通信之前,必须要先获取它的一个代理对象,即Client组件事先要知道Service组件的存在。然而,在广播机制中,广播发送者事先不需要知道广播接收者是存在的,这样就可以降低广播接收者和发送者之间的耦合度,得到模块分离。**
- **3、广播机制是一种基于消息发布和订阅的事件驱动模型,广播发送者负责发布消息,而广播接收者需要先订阅消息,然后才能收到消息。**
- **4、广播机制存在一个注册中心,它是由ActivityManagerService来担当的,广播接收者订阅消息的表现形式就是将自己注册到ActivieyManagerService中,并且指定要接收的广播的类型,当广播发送者向广播接收者发送一个广播时,这个广播首先发送到ActivityManagerService,然后ActivityManagerService可根据这个类型找到相应的广播接收者,最后将这个广播发送给它们处理。**
- **5、广播接收者的注册分为静态注册和动态注册,广播的发送方式分为有序和无序两种**
- **6、广播的生命周期,从对象调用它开始,到onReceiver方法执行完成之后结束。另外,每次广播被接收后会重新创建BroadcastReceiver对象,并在onReceiver方法中执行完就销毁,如果BroadcastReceiver的onReceiver方法中不能在10秒内执行完成,Android会出现ANR异常。所以不要在BroadcastReceiver的onReceiver方法中执行耗时的操作。**
- **7、如果需要在BroadcastReceiver中执行耗时的操作,可以通过Intent启动Service来完成。但不能绑定Service。特别是,您可能无法从一个BroadcastReceiver中显示一个对话框,或绑定到服务。对于前者,则应该使用NotificationManager的API。对于后者,你可以使用Context.startService()来启动一个Service。**
##BroadCastReceiver注册流程
先看一张时序图:

首先得有一个广播类,以下叫MyBroadCastReceiver:

有一个TestBroadCastActivity的类:

通过动态注册的方式注册了一个MyBroadCastReceiver广播类,以上就是一个广播的注册过程。
##BroadCastReceiver发送流程
先看下面两张时序图(ps:太长,只能分开截图):发送过程远比注册过程复杂的多


广播的发送过程:
- **1、广播发送者,即一个Activity组件或者一个service组件,将一个特定类型的广播发送给ActivityManagerService;**
- 2 、ActivityManagerService接收到一个广播之后,首先找到与这个广播对应的广播接收者,然后将他们添加一个广播调度队列中,最后向
ActivityManagerService发送一个类型为BROADCAST_INTENT_MSG的值,这时广播对发送者来说,一个广播发送过程就完成了;
- **3、当发送到ActivityManagerService所运行的线程的消息队列中BROADCAST_INTENT_MSG消息被处理时,ActivityManagerService就会从广播调度队列中找到需要的广播的接收者,并且将对应的广播发送给它们所运行的应用程序进程。**
- **4、广播接收者所运行在的应用程序进程接收到ActivityManagerService发送过来的广播之后,并不是直接将接受到的广播分发给广播接收者来处理,而是将接收到的广播封装成一个消息,并且发送到主线程的消息队列中,当这个消息被处理时,应用程序进程才会将它所描述的广播发送给相应的广播接收者处理。**
- **5、ActivityManagerService向一个应用程序发送一个广播时,采用的是异步进程间通信,Binder驱动结构体中binder_node时提到,发送给一一个Binder实体对象的所有异步事务都是保存在一个异步事务队列中的,由于保存在一个异步事务队列中的异步事务在同一时刻只有一个会得到处理,即只有位于队列头部的异步事务才会得到处理,因为,ActivityManagerService就可以保证它发送给同一个应用程序的所有都可以按照发送顺序来串行地接收和处理。**
以上就是广播的注册发送过程,ContentProvider不再分析,下篇将正式进入插件占坑,四大组件动态化注册分析。
================================================
FILE: DOC/hejunlin/插件占坑,四大组件动态注册前奏(二) 系统Service的启动流程.md
================================================
前言:为什么要了解系统Activity,Service,BroadCastReceiver,ContentProvider的启动流程,这是一个对于即将理解插件中的四大组件动态注册,占坑的前提,如果不了解的话,那么很难了解插件hook哪些东西,又是如何骗过AMS来启动Activity,Service,BroadCastReceiver,ContentProvider?
本节主要记录系统Service的启动流程:
先看时序图:

与Activity组件的启动方式很像,Service启动分为隐式和显式两种,对于隐式启动Service组件来说,我们只需要知道它的组件名称,而对于显示的Service组件来说,需要知道它的类名称。
以一个后台播放音乐场景来说明:
通过实现一个MyService来实现一个异步任务来播放后台音乐
MyActivity.java


MyService.java

MyActivity组件绑定MyService的过程:
- **1.MyActivity向ActivityManagerService发送一个绑定CounterService组件的进程间通信请求。**
- **2.ActivityManagerService发现用来运行MyService组件的应用程序进程即为MyActivity组件所运行的应用程序进程,因此,它就直接通知应用程序进程将MyService启动起来。**
- **3.MyService组件启动起来后,ActivityManagerService就请求它返回一个Binder本地对象,以便MyActivity可以通过这个Binder本地对象来和MyService组件建立连接。**
- **4.ActivityManagerService将前面从MyService组件中获得的一个Binder本地对象发送给MyActivity组件。**
- **5.MyActivity组件获得了ActivityManagerService给它发送的Binder本地对象之后,就可以通过它来获得MyService组件的一个访问接口,MyActivity组件之后就可以通过这个访问接口来使用MyService组件所提供的服务,这就相当于将MyService绑定在了MyActivity中了。**
那service在系统中绑定是如何的呢?
同样看下时序图:


客户端组件启动Server组件的过程:
- **1.Client组件启动ActivityManagerService发送一个启动Server组件的进程间通信请求。**
- 2.ActivityManagerService发现用来运行Server组件的应用程序进程不存在,因此,它就会首先将Server组件的信息保存下来,接着再
创建一个新的应用程序进程
- **3.新的应用程序启动完成之后,就会向ActivityManagerService发送一个启动完成进程间通信请求,以便ActivityManagerServices可以继续执行启动Service组件的操作。**
- **4.ActitivtyManagerService将2中保存下来的Service组件信息发送级第2步创建的应用程序进程,以便它可以将Server组件启动起来。**
================================================
FILE: DOC/hejunlin/插件开发之360 DroidPlugin源码分析(一)初识.md
================================================
插件开发之360 DroidPlugin源码分析(一)初识
###DroidPlugin的是什么?
一种新的插件机制,一种免安装的运行机制,是一个沙箱(但是不完全的沙箱。就是对于使用者来说,并不知道他会把apk怎么样), 是模块化的基础。
###DroidPlugin的缺点是什么?
- a.通知栏限制(无法在插件中发送具有自定义资源的Notification,例如: 1. 带自定义RemoteLayout的Notification 2. 图标通过R.drawable.XXX指定的通知(插件系统会自动将其转化为Bitmap)
- b.安全性担忧(可以修改,hook一些重要信息)
- c.机型适配(不是所有机器上都能行,因为大量用反射相关,如果rom厂商深度定制了framework层,反射的方法或者类不在,容易插件运用失败)
- d. 需要预先注册权限(在Library中申请了原生系统所有的权限)
- e. 无法在插件中注册一些具有特殊Intent Filter的Service、Activity、BroadcastReceiver、ContentProvider等组件以供Android系统、已经安装的其他APP调用。
- f. 缺乏对Native层的Hook,对某些带native代码的apk支持不好,可能无法运行。比如一部分游戏无法当作插件运行。
###DroidPlugin的特点是什么?
- a.免安装(就是如果只要从网上下载一个apk,不用安装apk,在插件机制下,就能运行)
- b.无需修改源码(因为大量反射,代理,Binder相关,这些足以骗过framework层)
- c.二进制级别隔离
- d.插件之间可以相互调用
- e.解除耦合
- f.静默安装,就是前面说的不用安装,就可在插件机制中运行apk
- g.崩溃隔离,插件崩溃,对主应用来说,不会有明显影响
- h.还原插件自己的多进程机制,适配性
- i.模块隔离,如可以把UI和控制逻辑进行隔离,控制逻辑可用插件化的方式
###官方说明:
- 支持Androd 2.3以上系统
- 插件APK完全不需做任何修改,可以独立安装运行、也可以做插件运行。要以插件模式运行某个APK,你无需重新编译、无需知道其源码。
- 插件的四大组件完全不需要在Host程序中注册,支持Service、Activity、BroadcastReceiver、ContentProvider四大组件
- 插件之间、Host程序与插件之间会互相认为对方已经"安装"在系统上了。
- API低侵入性:极少的API。HOST程序只是需要一行代码即可集成Droid Plugin
- 超强隔离:插件之间、插件与Host之间完全的代码级别的隔离:不能互相调用对方的代码。通讯只能使用Android系统级别的通讯方法。
- 支持所有系统API
- 资源完全隔离:插件之间、与Host之间实现了资源完全隔离,不会出现资源窜用的情况。
- 实现了进程管理,插件的空进程会被及时回收,占用内存低。
- 插件的静态广播会被当作动态处理,如果插件没有运行(即没有插件进程运行),其静态广播也永远不会被触发。
###DroidPlugin的的基本原理是什么?
- a.共享进程:为android提供一个进程运行多个apk的机制,通过API欺骗机制瞒过系统
- b.占坑:通过预先占坑的方式实现不用在manifest注册,通过一带多的方式实现服务管理
- c.Hook机制:动态代理实现函数hook,Binder代理绕过部分系统服务限制,IO重定向(先获取原始Object-->Read,然后动态代理Hook Object后-->Write回去,达到瞒天过海的目的)
插件Host的程序架构:

下一篇开始分析基本原理中的Hook机制
---
================================================
FILE: DOC/hejunlin/插件开发之360 DroidPlugin源码分析(三)Binder代理.md
================================================
- **Hook机制中Binder代理类关系图**
- **Hook机制中Binder代理时序图**
- **MyServiceManager**
- **ServiceManagerCacheBinderHook**
- **ServiceManagerBinderHook**
- **BinderHook**
##Hook机制中Binder代理类关系图

##Hook机制中Binder代理时序图


##MyServiceManager

- **mOriginServiceCache:这里存储的是原始的service cache。每个ActivityThread在bindApplication()的时候,会从ServiceManager那边获得一个service cache(可以减少和Binder代理之间通信,系统Binder是一个专门的BinderProxy和把上层的service和Binder driver进行IPC),每次要和某个service通信时,会先检查这个cache里有没有代理对象,如果有的话就直接用,不需要再和ServiceManager进行一次binder交互了。**
- **mProxiedServiceCache:这里存储的就是service cache的代理对象了,因为我们要hook这些binder和上层(serviceConnection时会转成IBinder接口)调用,所以必须把service cache也替换成我们的代理对象,每次调用都会走进ServiceManagerCacheBinderHook对象的invoke()方法。**
- **mProxiedObjCache:这里存储的是所有的proxyservice Object,那原始的service对象放在哪里呢?其实是在BinderHook的mOldObj里。**
##ServiceManagerCacheBinderHook



前面把service cache存起来,下次如果要真正和service进行通信,通过getOriginService()把原始的service cache拿出来用就行了。
##ServiceManagerBinderHook

这个类继承自ProxyHook,主要是用来hook住getService()和checkService()这两个API。如果这两个API被调用,并且在mProxiedObjCache发现有对应的代理对象,则直接返回这个代理对象。
##BinderHook


先调用ServiceManagerCacheBinderHook的onInstall()方法更新一下service cache,然后生成一个新的代理对象放到mProxiedObjCache里。这样下次不管是从cache里取,还是直接通过binder调用,就都会返回我们的代理对象。
Binder代理其实在android 系统中也是一个十分重要的角色。
这部分可以从网上搜下相关资料。360 plugin 的Binder代理就是借鉴了系统的Binder相关。
================================================
FILE: DOC/hejunlin/插件开发之360 DroidPlugin源码分析(二)Hook机制.md
================================================
前言:新插件的开发,可以说是为插件开发者带来了福音,虽然还很多坑要填补,对于这款牛逼的插件机制,一直想找个时间分析和总结下它的code,话不多说,直接入正题,本文是分析../hook/handle及../hook/proxy下代码,../hook/binder单独分析
- **Hook机制的包结构关系**
- **Hook机制的类图关系**
- **Hook机制的时序图关系**
- **Manifest权制申请**
- **基类Hook做了什么?**
- **HookedMethodHandler**
- **基类BaseHookHandle和Hook有什么关系?**
- **ProxyHook能干什么?**
- **实例-如何hook IPackageManager**
##Hook机制的包结构关系

##Hook机制类图关系

首先定义了一个基类Hook,抽象类,外部可以通过setEnable()方法来使能否hook。声明了onInstall和onUnInstall及相关的方法,子类可以覆盖这些方法完成相应的车间机床,这里相当于提供一个车间,机床上的具体操作什么由子类去自己实现。
##Hook机制的时序图关系

##Manifest权限申请
插件管理服务类声明:

权限申请:

##基类Hook做了什么?

##ProxyHook

ProxyHook继承自Hook,实现了InvocationHandler接口。它有一个setOldObj()方法,用来保存原始对象。新的代理对象可以看到在代码中是如何实现的(动态代理)
##BaseHookHandle


接上面ProxyHook中的invoke()方法,mHookHandles是一个BaseHookHandle对象,内部包含了一个Map,可以根据API名映射到对应对应的HookedMethodHandler对象。这个Map由其子类IXXXHookHandle在初始化的时候进行填充。
紧接着调用HookedMethodHandler的doHookInner()方法:
##HookedMethodHandler

##ReplaceCallingPackageHookedMethodHandler

##IO重定向

##递归遍历

##以IPackageManager为例
IPackageManagerHook:Hook所有IPackageManager的方法
IActivityManagerHookHandle:安装所有被Hook的方法的处理对象,加入到Map中
IPackageManagerHandle.checkSignatures:这是一个内部类,继承HookedMethodHandler, 专门校验签名的。以此,还有各种各样的PackageManger原生中的方法,在这都变成了一个内部类继承了HookedMethodHandler.上图:
IPackageManagerHookHandle:

================================================
FILE: DOC/hejunlin/插件开发之360 DroidPlugin源码分析(五)Service预注册占坑.md
================================================
在了解系统的activity,service,broadcastReceiver的启动过程后,今天将分析下360 DroidPlugin是如何预注册占坑的?本篇文章主要分析Service预注册占坑,Service占了坑后又是什么时候开始瞒天过海欺骗AMS的?先看下Agenda:
- **AndroidManifest.xml中概览**
- **Service中关键方法被hook时机**
- **startService被hook**
- **瞒天过海流程图**
- **认识ServiceManager**
##AndroidMainfest.xml中概览

android:process=":PluginP02" 表示自定义一个名为PluginP02的进程,该属性一旦设置, 那么App启动之后, Service肯定会以远程服务方式启动, ---- 可通过adb shell ps 就可以看到有一个独立的进程启动了.
项目 Package为 com.morgoo.droidplugin , 并设置 android:process=":PluginP02", 那么App运行时, 通过 adb shell ps | grep com.morgoo.droidplugin , 可以看到有两个进程:

##startService被hook
IActivityManagerHookHandle.startService方法

replaceFirstServiceIntentOfArgs()

接下来我们继续回到StartService类中,看下afterInvoke方法

stopService,bindService,unbindService,setServiceForeground都是类似逻辑,可从源码中证实。
在前一篇[《插件开发之360 DroidPlugin源码分析(四)Activity预注册占坑》](http://blog.csdn.net/hejjunlin/article/details/52258434),我们曾了解到,8个进程中的service在预注册占坑,在AndroidManifest.xml中只有一个,那如果插件要启动多个service怎么办?这是第一个问题,而我们知道所有和服务相关的都要在系统的systemServer进程中进行注册,难道DroidPlugin要逆天的本事?这是第二个问题
我们从代码中发现有一个ServceManager,这和android系统中大管家ServiceManager相差一个i,难道要改大管家的职责?又多了一个疑惑
仔细看了下ServceManager中的代码:



以上代码可总结为:(以虚线分上下两部分)
1.上部分主要是ServceManager单例及有一个handleXXX相关的方法,下部分主要是Service的一些生命周期方法。
2.我们基本可以确定之前问题2和问题3的答案了,没有那么逆天的本事来操作ServiceManager,也不能修改大管家ServiceManager的职责
3.那问题又来了,这个类到底是做啥的?还起一个叫ServceManager的名字,
以hanldeOnTaskRemoveOne方法为例看看:

接着再看下ServceManager中的onBind方法:

然后调到handleOnBindOne方法中,我们前面分析了一个handleOnTaskRemovedOne方法,下面1-7步骤套路都是一样,主要在return时,直接调用service自身的onBind了,这和我们平时在Activity中new Intent,然后把这个intent传到onBind中.

那么问题来了,还要这么一个类倒腾来干啥呢?还记得上面有一处逻辑service为null时,就调用了handleCreateServiceOne,好戏在这里:


看了上面的分析后,我们再去回想第一个问题,那如果插件要启动多个service怎么办?不知道不没有注意到mTokenServices,mNameService,mServiceTaskIds这些成员变量,它们都是Map,key不一样,value全是Service,如个有多个service在插件中启动了,mTokenServices,mNameService,mServiceTaskIds这些成员变量分别掌握了Service的Token,name,及任务id(通过token拿到的)。那岂不是已经在管理这些多个service了。至于附属于这个类起的名字,叫什么都无所谓。
以上可用如下流程图表示:

前面一直有个问题解释的不彻底,就是问题3,ServceManager是否担当了修改系统大管家ServiceManager的职责?接下来,我们就稍微了解下系统大管家ServiceManager是做什么的?(PS: ServiceManager和Binder机制一样,不是一天两个就能研究的清楚的)
##认识ServiceManager
Android系统Binder机制的总管是ServiceManager,所有的Server(System Server)都需要向它注册,应用程序需要向其查询相应的服务。平时,我们在studio上的DDMS中调试程序时,下图这个就是ServiceManager
这里以Java层加入ServiceManager及getService为数据流分析一下。
复习一下典型的Binder模式,有利于后面的理解:
1、客户端通过某种方式得到服务器端的代理对象。从客户端角度看来代理对象和他的本地对象没有什么差别。它可以像其他本地对象一样调用其方法,访问其变量。
2、客户端通过调用服务器代理对象的方法向服务器端发送请求。
3、代理对象把用户请求通过Android内核(Linux内核)的Binder驱动发送到服务器进程。
4、服务器进程处理用户请求,并通过Android内核(Linux内核)的Binder驱动返回处理结果给客户端的服务器代理对象。
5、客户端收到服务器端的返回结果。
JAVA层代码分析:
ServiceManager.java (frameworks\base\core\java\android\os)
对于xxxManager获取服务端service基本如此用法:
举例:
利用ContextImpl.java中的 public Object getSystemService(String name)

然后再调用:ServiceManager.getService(ServiceName);获取相应的服务端

知道了客户端获取一个Service的方法之后,我们回到ServiceManager的服务端:

BinderInternal.getContextObject() @ BinderInternal.java 是一个native 函数:
android_os_BinderInternal_getContextObject @ android_util_Binder.cpp
返回一个 BinderProxy对象保存到类成员mRemote(ServiceManagerProxy类成员)
public abstract class ServiceManagerNative extends Binder implements IServiceManager
ServiceManagerNative 继承自 Binder 并实现了 IServiceManager 接口,利用 asInterface()则提供一个 ServiceManagerProxy 代理对象使用
class ServiceManagerProxy implements IServiceManager
定义了类ServiceManagerProxy(代理),ServiceManagerProxy继承自IServiceManager,并实现了其声明的操作函数,只会被ServiceManagerNative创建,它实现了IServiceManager的接口,IServiceManager提供了getService和addService两个成员函数来管理系统中的Service。

上面代码总结如下:Java层先利用Parcel对象将数据进行序列化,然后利用transact将数据传给binder驱动,就是上面mRemote.transact,mRemote在JNI层是一个叫BpBinder的对象:
JNI层代码分析:
android_util_Binder.cpp

每当我们利用BpBinder的transact()函数发起一次跨进程事务时,其内部其实是调用IPCThreadState对象的transact()。BpBinder的transact()代码如下:

到此,不再向下深究,具体想了解可以看Binder机制及IPC相关内容。
所以,到这把第2个问题彻底弄明白了,ServiceManager和ServiceManager根本不是一回事。到次,Service的瞒天过海得以实现,接着,就是介绍时候说的那样无需修改源码,多进程,多service等功能。另外ContentProvider及BroadCast原理是类似,不再进行分析。
下篇将开始分析包管理(宿主插件和插件包名有什么规则),APK解析(为什么可以免安装),进程管理(能确保隐藏起来,不会在process轻易被kill)
================================================
FILE: DOC/hejunlin/插件开发之360 DroidPlugin源码分析(四)Activity预注册占坑.md
================================================
在了解系统的activity,service,broadcastReceiver的启动过程后,今天将分析下360 DroidPlugin是如何预注册占坑的?本篇文章主要分析Activity预注册占坑,Activity占了坑后又是什么时候开始瞒天过海欺骗AMS的?先看下Agenda:
- **AndroidMainfest.xml中概览**
- **Activity中关键方法被hook时机**
- **startActivity被hook**
- **handelPerformActivity被hook**
- **Activity预注册占坑整体流程图**
- **瞒天过海,冒充真实身份,欺骗AMS**
##AndroidMainfest.xml中概览
我们知道所有能用的四大组件都要在Manifest中注册声明,第一步,先看AndroidManifest.xml,虽然在说hook机制时,也有提及过,但是毕竟没细致分析,话不多说,看代码上图:

然后看下各个属性的意思

表示一个activity1原来属于task1,但是如果task2启动起来的话,activity1可能不再属于task1了,转而投奔task2去了。

功能:启动硬件加速
缺点:占用内存
特点:可以在Application、Activity、Window、View四个级别进行硬件加速控制
从Android3.0(API Level 11)开始,Android 2D渲染管道能够更好的支持硬件加速。硬件加速执行的所有的绘图操作都是使用GPU在View对象的画布上来进行的。因为启用硬件加速会增加资源的需求,因此这样的应用会占用更多的内存。
启用硬件加速的最容易的方法是给整个应用程序都打开全局硬件加速功能。如果应用程序只使用标准的View和Drawable,那么打开全局硬件加速不会导致任何的不良的绘制效果。但是,因为硬件加速并不支持所有的2D图形绘制操作,所以对于那些使用定制的View和绘制调用的应用程序来说,打开全局硬件加速,可以会影响绘制效果。问题通常会出现在对那些不可见的元素进行了异常或错误的像素渲染。为了避免这种问题,Android提供以下级别,以便可选择性的启用或禁止硬件加速:
控制硬件加速,能够用以下级别来控制硬件加速:
1、Application级别
在应用的Android清单文件中,把下列属性添加到元素中,来开启整个应用程序的硬件加速。
2、Activity级别
如果应用程序不能够正确的使用被打开的全局硬件加速,那么也可以对Activity分别进行控制。在元素中使用android:hardwareAccelerated属性,能够启用或禁止Activity级别的硬件加速。以下示例启用全局的硬件加速,但却禁止了一个Activity的硬件加速。
3、Window级别
如果需要更细粒度的控制,就可以使用下列代码来针对给定的窗口来启用硬件加速:
注意:当前不能在Window级别禁止硬件加速。

4、View级别
能够使用下列代码在运行时针对一个独立的View对象来禁止硬件加速:

注意:当前不能在View级别开启硬件加速。View层除了禁止硬件加速以外,还有其他的功能,更多的相关信息请看本文的“View层”。


以上就是声明属性的含义说明,作为背景了解即可。重点看下面的分析

Manifest中注册了8个进程,加上主进程共9个
然后第每个进程下面又有26个Activity注册,一个service,一个contentprovider,那么问题来了,搞这么多注册在manifest做什么用?仔细分类:就两类一类是Activity,一类是Dialog,我们知道Dialog是建立在Activity之上的,如果Activity被finish或destory后,就会报出异常:android.view.WindowManager$BadTokenException: Unable to add window — token android.os.BinderProxy@438e7108 is not valid; is your activity running?
附[《插件占坑,四大组件动态注册前奏(一) 系统Activity的启动流程》](http://blog.csdn.net/hejjunlin/article/details/52190050)(也可点击链接过去看详细过程)的activity的启动时序列图:


##Activity中关键方法被hook时机
其中startActivity()和handleLanchActivity()是被DroidPlugin 要欺骗系统的两个主要方法:
第一个方法是最被经常使用的startActivity(),hook机制见[《插件开发之360 DroidPlugin源码分析(二)Hook机制》](http://blog.csdn.net/hejjunlin/article/details/52124397)中分析,主要是通过Java的反射机制替换掉IActivityManager全局对象,具体IActivityManagerHookHandle的onInstall()方法如下:


第二个方法是handleLaunchActivity(),这个方法属于ActivityThread的一个叫做H的内部类,前面讲Activity启动时,已埋下伏笔,可以参考[《插件占坑,四大组件动态注册前奏(一) 系统Activity的启动流程》](http://blog.csdn.net/hejjunlin/article/details/52190050),如果学过中间人攻击协议的话,我们知道,现个通信双方发出消息后,进行消息验证,如果中间人拦截相关协议内容,通过一个代理进行转发出去,从而达到欺骗的目的,这里暂且理解handleLanchActivity被中间人攻击了,当启动handleLanchActivity时,被DroidPlugin hook后,那多人可能会想,你怎么hook住hanleLanchActivity呢?别忘了,我们可是在Manifest占了一堆坑的。要是不好理解,可以参看《插件前奏-android黑科技 hook介绍 :http://blog.csdn.net/hejjunlin/article/details/52091833》,可能更直观些,哪在DroidPlugin中,如何在代码中瞒天过海的呢?
我们可以看下:PluginCallbackHook.java,其中有一个onInstall()方法:

如上代码也有注释,可总结为:
1.DroidPlugin不是完全攻击mH这个内部类,而是把mH的mCallback成员变量攻击了,然后替换成了一个PluginCallback对象,进行消息分发,那么就可以在在PluginCallback的handleMessage()里任意拦截想要分发的消息,来欺骗AMS。经过中间人这么一闹腾,那就能达到控制这个区域的目的了。
最狠的看下面:
上面代码中,有一个mH的mCallback,是被拦截攻击了吧,既然被拦截后又要冒充一个担当mH的mCallback职责相关,(这里暂且夸张的说)那肯定得扒了它身上的某些特性放到冒充的mCallback吧,如身份验证相关之类,所以那原来的mCallback丢了它的身份相关,不就是废了,暂且理解为mCallback为null,实际上有mCallback在未赋值之前,初始化时,本身也是null。然后看下PluginCallback的handleMessage()方法:(ps: PluginCallback简直就是仿照ActivityThread中的H内部类写的,几乎逻辑一样,具体可看系统源码证实)

这里只拦截了一个消息类型为LAUNCH_ACTIVITY(ActivityThread中的H内部类中会有很多消息类型,也包含LAUNCH_ACTIVITY)。mCallback不为null,就是发一些伪装的消息(因为我们刚拦截了mCallback),如果为null,返回false,这样就会会再通过mH调用回真正ActivityThread的handleLaunchActivity()。(ps:系统发的消息没什么卵用时,我们就不去拦截,暂且理解为这样)
以上就是两个方法怎么被hook相关分析,也可参考在Hook机制举例为IPackageManager的验证签名被hook的过程,接下来就是要看hook中做了什么事?附一张Activity预注册占坑整体流程图:

前面我们都是在说DroidPlugin怎么用中间人攻击方式,拦截了startActivity()方法和hanleLanchActivity()方法,接下来要看下拦截了后,怎么把这种身份角色搞变化了(就是一个怎么扮演冒充的角色过程):
1.首先得找一个和真实的人像的角色,这时启用的我们备用人员,也就是事先占的坑stub.ActivityStubxxx。
2.真实的角色身上有某些特定的特性,如爱抽烟,头发乱糟糟的,像Activity中Intent作为一个extra传到另一个Activity时,还有一些自己的lanchmode(启动方式),theme(主题),这些都是Activity的一些特性,所以stub.ActivityStubxxx也得有这些,否则怎么能达到冒充呢,这些我们在代码中早就写好了,所有的那些注册的26个备用人员都是继承ActivityStub,而ActivityStub是直接继承Activity,那还说啥呢,不就是天然的冒充么?说这么多了,直接看代码IActivityManagerHookHandle$startActvity:
这是一个静态内部类,继承ReplaceCallingPackageHookedMethodHandler,重写了beforeInvoke方法,暂且理解为在冒充之前的一些准备工作,如下:

接着再看beforeStartActivity方法:

就是判断了下Activity的启动模式,接着都调入doFinshIt(mRunningXXXActivityList),继续看此方法:

STUB_NO_ACTIVITY_MAX_NUM为4,上面方法总结为:runningActivityList(备用activity的list的总数)大于等于3时,就把最早进入activityRecord栈中的那个finish掉,因为坑就那么多,要是都占着不干活,那要它干嘛?
##瞒天过海,冒充真实身份,欺骗AMS
前面这些,还是小打小闹,接下来看一个核心方法,就是beforeInvoke中的doReplaceIntentForStartActivityAPILow方法:

前面我们说了,欺骗了两个方法,上面说的都是startActivity(),接下来看另个一个方法handleLanchActivity(), 这个方法在哪呢?我们前面说过有一个仿照ActivityThread中H内部类的class叫PluginCallBack,对,handleLaunchActivity就是在接到handleMessage中消息类型为LANCH_ACTIVITY时调用的:

以上就是Activity预注册占坑,并欺骗AMS的过程,下篇分析Service预注册占坑。
如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易
================================================
FILE: DOC/tianweishu/.gitignore
================================================
.DS_Store
================================================
FILE: DOC/tianweishu/Activity生命周期管理.md
================================================
# Activity生命周期管理
之前的 [Android插件化原理解析][1] 系列文章揭开了Hook机制的神秘面纱,现在我们手握倚天屠龙,那么如何通过这种技术完成插件化方案呢?具体来说,插件中的Activity,Service等组件如何在Android系统上运行起来?
在Java平台要做到动态运行模块、热插拔可以使用`ClassLoader`技术进行动态类加载,比如广泛使用的`OSGi`技术。在Android上当然也可以使用动态加载技术,但是仅仅把类加载进来就足够了吗?`Activity`,`Service`等组件是有生命周期的,它们统一由系统服务`AMS`管理;使用`ClassLoader`可以从插件中创建Activity对象,但是,一个没有生命周期的Activity对象有什么用?所以在Android系统上,仅仅完成动态类加载是不够的;我们需要想办法把我们加载进来的Activity等组件交给系统管理,让`AMS`赋予组件生命周期;这样才算是一个有血有肉的完善的插件化方案。
接下来的系列文章会讲述 DroidPlugin对于Android四大组件的处理方式,我们且看它如何采用Hook技术坑蒙拐骗把系统玩弄于股掌之中,最终赋予Activity,Service等组件生命周期,完成借尸还魂的。
<!-- more -->
首先,我们来看看DroidPlugin对于`Activity`组件的处理方式。
阅读本文之前,可以先clone一份 [understand-plugin-framework][2],参考此项目的intercept-activity模块。另外,如果对于Hook技术不甚了解,请先查阅我之前的文章:
1. [Hook机制之动态代理][3]
2. [Hook机制之Binder Hook][4]
3. [Hook机制之AMS&PMS][5]
## AndroidManifest.xml的限制
读到这里,或许有部分读者觉得疑惑了,启动Activity不就是一个`startActivity`的事吗,有这么神秘兮兮的?
启动Activity确实非常简单,但是Android却有一个限制:**必须在AndroidManifest.xml中显示声明使用的Activity**;我相信读者肯定会遇到下面这种异常:
```java
03-18 15:29:56.074 20709-20709/com.weishu.intercept_activity.app E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.weishu.intercept_activity.app, PID: 20709
android.content.ActivityNotFoundException: Unable to find explicit activity class {com.weishu.intercept_activity.app/com.weishu.intercept_activity.app.TargetActivity}; have you declared this activity in your AndroidManifest.xml?
```
『必须在AndroidManifest.xml中显示声明使用的Activity』这个硬性要求很大程度上限制了插件系统的发挥:假设我们需要启动一个插件的Activity,插件使用的Activity是无法预知的,这样肯定也不会在Manifest文件中声明;如果插件新添加一个Activity,主程序的AndroidManifest.xml就需要更新;既然双方都需要修改升级,何必要使用插件呢?这已经违背了动态加载的初衷:不修改插件框架而动态扩展功能。
能不能想办法绕过这个限制呢?
束手无策啊,怎么办?借刀杀人偷梁换柱无中生有以逸待劳乘火打劫瞒天过海...等等!偷梁换柱瞒天过海?貌似可以一试。
我们可以耍个障眼法:既然AndroidManifest文件中必须声明,那么我就声明一个(或者有限个)替身Activity好了,当需要启动插件的某个Activity的时候,先让系统以为启动的是AndroidManifest中声明的那个替身,暂时骗过系统;然后到合适的时候又替换回我们需要启动的真正的Activity;所谓瞒天过海,莫过如此!
现在有了方案了,但是该如何做呢?兵书又说,知己知彼百战不殆!如果连Activity的启动过程都不熟悉,怎么完成这个瞒天过海的过程?
## Activity启动过程
启动Activity非常简单,一个`startActivity`就完事了;那么在这个简单调用的背后发生了什么呢?Look the fucking source code!
关于Activity 的启动过程,也不是三言两语能解释清楚的,如果按照源码一步一步走下来,插件化系列文章就不用写了;所以这里我就给出一个大致流程,只列出关键的调用点(以Android 6.0源码为例);如果读者希望更详细的讲解,可以参考老罗的 [ Android应用程序的Activity启动过程简要介绍和学习计划][6]
首先是Activity类的`startActivity`方法:
```java
public void startActivity(Intent intent) {
startActivity(intent, null);
}
```
跟着这个方法一步一步跟踪,会发现它最后在`startActivityForResult`里面调用了Instrument对象的`execStartActivity`方法;接着在这个函数里面调用了ActivityManagerNative类的`startActivity`方法;这个过程在前文已经反复举例讲解了,我们知道接下来会通过Binder IPC到`AMS`所在进程调用`AMS`的`startActivity`方法;Android系统的组件生命周期管理就是在`AMS`里面完成的,那么在`AMS`里面到底做了什么呢?
ActivityManagerService的`startActivity`方法如下:
```
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags,
String profileFile, ParcelFileDescriptor profileFd, Bundle options) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode,
startFlags, profileFile, profileFd, options, UserHandle.getCallingUserId());
}
```
很简单,直接调用了`startActivityAsUser`这个方法;接着是`ActivityStackSupervisor`类的`startActivityMayWait`方法。这个ActivityStackSupervisor类到底是个啥?如果仔细查阅,低版本的Android源码上是没有这个类的;后来AMS的代码进行了部分重构,关于Activity栈管理的部分单独提取出来成为了`ActivityStackSupervisor`类;好了,继续看代码。
startActivityMayWait这个方法前面对参数进行了一系列处理,我们需要知道的是,在这个方法内部对传进来的Intent进行了解析,并尝试从中取出关于启动Activity的信息。
然后这个方法调用了startActivityLocked方法;在startActivityLocked方法内部进行了一系列重要的检查:比如权限检查,Activity的exported属性检查等等;我们上文所述的,启动没有在Manifestfest中显示声明的Activity抛异常也是这里发生的:
```
if (err == ActivityManager.START_SUCCESS && aInfo == null) {
// We couldn't find the specific class specified in the Intent.
// Also the end of the line.
err = ActivityManager.START_CLASS_NOT_FOUND;
}
```
这里返回ActivityManager.START_CLASS_NOT_FOUND之后,在Instrument的execStartActivity返回之后会检查这个值,然后跑出异常:
```
case ActivityManager.START_CLASS_NOT_FOUND:
if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
throw new ActivityNotFoundException(
"Unable to find explicit activity class "
+ ((Intent)intent).getComponent().toShortString()
+ "; have you declared this activity in your AndroidManifest.xml?");
```
源码看到这里,我们已经确认了『必须在AndroidManifest.xml中显示声明使用的Activity』的原因;然而这个校检过程发生在`AMS`所在的进程`system_server`,我们没有办法篡改,只能另寻他路。
OK,我们继续跟踪源码;在startActivityLocked之后处理的都是Activity任务栈相关内容,这一系列ActivityStack和ActivityStackSupervisor纠缠不清的调用看下图就明白了;不明白也没关系: D 目前用处不大。

这一系列调用最终到达了ActivityStackSupervisor的realStartActivityLocked方法;人如其名,这个方法开始了真正的“启动Activity”:它调用了ApplicationThread的scheduleLaunchActivity方法,开始了真正的Activity对象创建以及启动过程。
这个ApplicationThread是什么,是一个线程吗?与ActivityThread有什么区别和联系?
不要被名字迷惑了,这个ApplicationThread实际上是一个Binder对象,是App所在的进程与AMS所在进程system_server通信的桥梁;在Activity启动的过程中,App进程会频繁地与AMS进程进行通信:
1. App进程会委托AMS进程完成Activity生命周期的管理以及任务栈的管理;这个通信过程AMS是Server端,App进程通过持有AMS的client代理ActivityManagerNative完成通信过程;
2. AMS进程完成生命周期管理以及任务栈管理后,会把控制权交给App进程,让App进程完成Activity类对象的创建,以及生命周期回调;这个通信过程也是通过Binder完成的,App所在server端的Binder对象存在于ActivityThread的内部类ApplicationThread;AMS所在client通过持有IApplicationThread的代理对象完成对于App进程的通信。
App进程与AMS进程的通信过程如图所示:
<img src="http://7xp3xc.com1.z0.glb.clouddn.com/201601/1458300329231.png" width="500"/>
App进程内部的ApplicationThread server端内部有自己的Binder线程池,它与App主线程的通信通过Handler完成,这个Handler存在于ActivityThread类,它的名字很简单就叫`H`,这一点我们接下来就会讲到。
现在我们明白了这个ApplicationThread到底是个什么东西,接上文继续跟踪Activity的启动过程;我们查看ApplicationThread的`scheduleLaunchActivity`方法,这个方法很简单,就是包装了参数最终使用Handler发了一个消息。
正如刚刚所说,ApplicationThread所在的Binder服务端使用Handler与主线程进行通信,这里的scheduleLaunchActivity方法直接把启动Activity的任务通过一个消息转发给了主线程;我们查看Handler类对于这个消息的处理:
```
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
```
可以看到,这里直接调用了ActivityThread的handleLaunchActivity方法,在这个方法内部有一句非常重要:
```
Activity a = performLaunchActivity(r, customIntent);
```
绕了这么多弯,我们的Activity终于被创建出来了!继续跟踪这个performLaunchActivity方法看看发生了什么;由于这个方法较长,我就不贴代码了,读者可以自行查阅;要指出的是,这个方法做了两件很重要的事情:
1. 使用ClassLoader加载并通过反射创建Activity对象
```
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
```
2. 如果Application还没有创建,那么创建Application对象并回调相应的生命周期方法;
```java
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
// ... 省略
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
```
Activity的启动过程到这里就结束了,可能读者还是觉得迷惑:不就是调用了一系列方法吗?具体做了什么还是不太清楚,而且为什么Android要这么设计?
方法调用链再长也木有关系,有两点需要明白:
1. 平时我们所说的Application被创建了,onCreate方法被调用了,我们或许并没有意识到我们所说的`Application, Activity`除了代表Android应用层通常所代表的“组件”之外,它们其实都是普通的Java对象,也是需要被构造函数构造出来的对象的;在这个过程中,我们明白了这些对象到底是如何被创建的。
2. 为什么需要一直与AMS进行通信?哪些操作是在AMS中进行的?其实`AMS`正如名字所说,管理所有的“活动”,整个系统的Activity堆栈,Activity生命周期回调都是由AMS所在的系统进程system_server帮开发者完成的;Android的Framework层帮忙完成了诸如生命周期管理等繁琐复杂的过程,简化了应用层的开发。
## 瞒天过海——启动不在AndroidManifest.xml中声明的Activity
### 简要分析
通过上文的分析,我们已经对Activity的启动过程了如指掌了;就让我们干点坏事吧 :D
对与『必须在AndroidManifest.xml中显示声明使用的Activity』这个问题,上文给出了思路——瞒天过海;我们可以在AndroidManifest.xml里面声明一个替身Activity,然后**在合适的时候**把这个假的替换成我们真正需要启动的Activity就OK了。
那么问题来了,『合适的时候』到底是什么时候?在前文[Hook机制之动态代理][3]中我们提到过Hook过程最重要的一步是**寻找Hook点**;如果是在同一个进程,`startActivity`到Activity真正启动起来这么长的调用链,我们随便找个地方Hook掉就完事儿了;但是问题木有这么简单。
Activity启动过程中很多重要的操作(正如上文分析的『必须在AndroidManifest.xml中显式声明要启动的Activity』)都不是在App进程里面执行的,而是在AMS所在的系统进程system_server完成,由于**进程隔离**的存在,我们对别的进程无能为力;所以这个Hook点就需要花点心思了。
这时候Activity启动过程的知识就派上用场了;虽然整个启动过程非常复杂,但其实一张图就能总结:

先从App进程调用`startActivity`;然后通过IPC调用进入系统进程system_server,完成Activity管理以及一些校检工作,最后又回到了APP进程完成真正的Activioty对象创建。
由于这个检验过程是在AMS进程完成的,我们对system_server进程里面的操作无能为力,只有在我们APP进程里面执行的过程才是有可能被Hook掉的,也就是第一步和第三步;具体应该怎么办呢?
既然需要一个显式声明的Activity,那就声明一个!**可以在第一步假装启动一个已经在AndroidManifest.xml里面声明过的替身Activity,让这个Activity进入AMS进程接受检验;最后在第三步的时候换成我们真正需要启动的Activity**;这样就成功欺骗了AMS进程,瞒天过海!
说到这里,是不是有点小激动呢?我们写个demo验证一下:『启动一个并没有在AndroidManifest.xml中显示声明的Activity』
### 实战过程
具体来说,我们打算实现如下功能:在MainActivity中启动一个并没有在AndroidManifest.xml中声明的TargetActivity;按照上文分析,我们需要声明一个替身Activity,我们叫它StubActivity;
那么,我们的AndroidManifest.xml如下:
```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.weishu.intercept_activity.app">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- 替身Activity, 用来欺骗AMS -->
<activity android:name=".StubActivity"/>
</application>
</manifest>
```
OK,那么我们启动TargetActivity很简单,就是个`startActivity`调用的事:
```java
startActivity(new Intent(MainActivity.this, TargetActivity.class));
```
如果你直接这么运行,肯定会直接抛出ActivityNotFoundException然后直接退出;我们接下来要做的就是让这个调用成功启动TargetActivity。
#### 狸猫换太子——使用替身Activity绕过AMS
由于`AMS`进程会对Activity做显式声明验证,因此在
启动Activity的控制权转移到`AMS`进程之前,我们需要想办法**临时**把TargetActivity替换成替身StubActivity;在这之间有很长的一段调用链,我们可以轻松Hook掉;选择什么地方Hook是一个很自由的事情,但是Hook的步骤越后越可靠——Hook得越早,后面的调用就越复杂,越容易出错。
我们可以选择在进入`AMS`进程的入口进行Hook,具体来说也就是Hook `AMS`在本进程的代理对象ActivityManagerNative。如果你不知道如何Hook掉这个AMS的代理对象,请查阅我之前的文章 [Hook机制之AMS&PMS][5]
我们Hook掉ActivityManagerNative对于startActivity方法的调用,替换掉交给AMS的intent对象,将里面的TargetActivity的暂时替换成已经声明好的替身StubActivity;这种Hook方式 [前文][5] 讲述的很详细,不赘述;替换的关键代码如下:
```java
if ("startActivity".equals(method.getName())) {
// 只拦截这个方法
// 替换参数, 任你所为;甚至替换原始Activity启动别的Activity偷梁换柱
// API 23:
// public final Activity startActivityNow(Activity parent, String id,
// Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
// Activity.NonConfigurationInstances lastNonConfigurationInstances) {
// 找到参数里面的第一个Intent 对象
Intent raw;
int index = 0;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Intent) {
index = i;
break;
}
}
raw = (Intent) args[index];
Intent newIntent = new Intent();
// 这里包名直接写死,如果再插件里,不同的插件有不同的包 传递插件的包名即可
String targetPackage = "com.weishu.intercept_activity.app";
// 这里我们把启动的Activity临时替换为 StubActivity
ComponentName componentName = new ComponentName(targetPackage, StubActivity.class.getCanonicalName());
newIntent.setComponent(componentName);
// 把我们原始要启动的TargetActivity先存起来
newIntent.putExtra(HookHelper.EXTRA_TARGET_INTENT, raw);
// 替换掉Intent, 达到欺骗AMS的目的
args[index] = newIntent;
Log.d(TAG, "hook success");
return method.invoke(mBase, args);
}
return method.invoke(mBase, args);
```
通过这个替换过程,在ActivityManagerNative的startActivity调用之后,system_server端收到Binder驱动的消息,开始执行ActivityManagerService里面真正的`startActivity`方法;这时候AMS看到的`intent`参数里面的组件已经是`StubActivity`了,因此可以成功绕过检查,这时候如果不做后面的Hook,直接调用
```java
startActivity(new Intent(MainActivity.this, TargetActivity.class));
```
也不会出现上文的ActivityNotFoundException
#### 借尸还魂——拦截Callback从恢复真身
行百里者半九十。现在我们的`startActivity`启动一个没有显式声明的Activity已经不会抛异常了,但是要真正正确地把TargetActivity启动起来,还有一些事情要做。其中最重要的一点是,我们用替身StubActivity临时换了TargetActivity,肯定需要在『合适的』时候替换回来;接下来我们就完成这个过程。
在AMS进程里面我们是没有办法换回来的,因此我们要等AMS把控制权交给App所在进程,也就是上面那个『Activity启动过程简图』的第三步。AMS进程转移到App进程也是通过Binder调用完成的,承载这个功能的Binder对象是IApplicationThread;在App进程它是Server端,在Server端接受Binder远程调用的是Binder线程池,Binder线程池通过Handler将消息转发给App的主线程;(我这里不厌其烦地叙述Binder调用过程,希望读者不要反感,其一加深印象,其二懂Binder真的很重要)我们可以在这个**Handler里面将替身恢复成真身**。
这里不打算讲述Handler 的原理,我们简单看一下Handler是如何处理接收到的Message的,如果我们能拦截这个Message的接收过程,就有可能完成替身恢复工作;Handler类的`dispathMesage`如下:
```java
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
```
从这个方法可以看出来,Handler类消息分发的过程如下:
1. 如果传递的Message本身就有callback,那么直接使用Message对象的callback方法;
2. 如果Handler类的成员变量`mCallback`存在,那么首先执行这个`mCallback`回调;
3. 如果`mCallback`的回调返回`true`,那么表示消息已经成功处理;直接结束。
4. 如果`mCallback`的回调返回`false`,那么表示消息没有处理完毕,会继续使用Handler类的`handleMessage`方法处理消息。
那么,ActivityThread中的Handler类`H`是如何实现的呢?`H`的部分源码如下:
```java
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case RELAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 以下略
}
}
```
可以看到`H`类仅仅重载了`handleMessage`方法;通过dispathMessage的消息分发过程得知,我们可以拦截这一过程:**把这个`H`类的`mCallback`替换为我们的自定义实现**,这样`dispathMessage`就会首先使用这个自定义的`mCallback`,然后看情况使用`H`重载的`handleMessage`。
这个`Handler.Callback`是一个接口,我们可以使用动态代理或者普通代理完成Hook,这里我们使用普通的静态代理方式;创建一个自定义的Callback类:
```java
/* package */ class ActivityThreadHandlerCallback implements Handler.Callback {
Handler mBase;
public ActivityThreadHandlerCallback(Handler base) {
mBase = base;
}
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
// ActivityThread里面 "LAUNCH_ACTIVITY" 这个字段的值是100
// 本来使用反射的方式获取最好, 这里为了简便直接使用硬编码
case 100:
handleLaunchActivity(msg);
break;
}
mBase.handleMessage(msg);
return true;
}
private void handleLaunchActivity(Message msg) {
// 这里简单起见,直接取出TargetActivity;
Object obj = msg.obj;
// 根据源码:
// 这个对象是 ActivityClientRecord 类型
// 我们修改它的intent字段为我们原来保存的即可.
/* switch (msg.what) {
/ case LAUNCH_ACTIVITY: {
/ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
/ final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
/
/ r.packageInfo = getPackageInfoNoCheck(
/ r.activityInfo.applicationInfo, r.compatInfo);
/ handleLaunchActivity(r, null);
*/
try {
// 把替身恢复成真身
Field intent = obj.getClass().getDeclaredField("intent");
intent.setAccessible(true);
Intent raw = (Intent) intent.get(obj);
Intent target = raw.getParcelableExtra(HookHelper.EXTRA_TARGET_INTENT);
raw.setComponent(target.getComponent());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
```
这个Callback类的使命很简单:**把替身StubActivity恢复成真身TargetActivity**;有了这个自定义的Callback之后我们需要把ActivityThread里面处理消息的Handler类`H`的的`mCallback`修改为自定义callback类的对象:
```java
// 先获取到当前的ActivityThread对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Field currentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
currentActivityThreadField.setAccessible(true);
Object currentActivityThread = currentActivityThreadField.get(null);
// 由于ActivityThread一个进程只有一个,我们获取这个对象的mH
Field mHField = activityThreadClass.getDeclaredField("mH");
mHField.setAccessible(true);
Handler mH = (Handler) mHField.get(currentActivityThread);
// 设置它的回调, 根据源码:
// 我们自己给他设置一个回调,就会替代之前的回调;
// public void dispatchMessage(Message msg) {
// if (msg.callback != null) {
// handleCallback(msg);
// } else {
// if (mCallback != null) {
// if (mCallback.handleMessage(msg)) {
// return;
// }
// }
// handleMessage(msg);
// }
// }
Field mCallBackField = Handler.class.getDeclaredField("mCallback");
mCallBackField.setAccessible(true);
mCallBackField.set(mH, new ActivityThreadHandlerCallback(mH));
```
到这里,我们已经成功地绕过`AMS`,完成了『启动没有在AndroidManifest.xml中显式声明的Activity』的过程;瞒天过海,这种玩弄系统与股掌之中的快感你们能体会到吗?
#### 僵尸or活人?——能正确收到生命周期回调吗
虽然我们完成了『启动没有在AndroidManifest.xml中显式声明的Activity 』,但是启动的TargetActivity是否有自己的生命周期呢,我们还需要额外的处理过程吗?
实际上TargetActivity已经是一个有血有肉的Activity了:它具有自己正常的生命周期;可以运行[Demo代码][2]验证一下。
这个过程是如何完成的呢?我们以`onDestroy`为例简要分析一下:
> 从Activity的`finish`方法开始跟踪,最终会通过ActivityManagerNative到`AMS`然后接着通过ApplicationThread到ActivityThread,然后通过`H`转发消息到ActivityThread的handleDestroyActivity,接着这个方法把任务交给performDestroyActivity完成。
在真正分析这个方法之前,需要说明一点的是:不知读者是否感受得到,App进程与`AMS`交互几乎都是这么一种模式,几个角色 ActivityManagerNative, ApplicationThread, ActivityThread以及Handler类`H`分工明确,读者可以按照这几个角色的功能分析`AMS`的任何调用过程,屡试不爽;这也是我的初衷——希望分析插件框架的过程中能帮助深入理解Android Framework。
好了继续分析performDestroyActivity,关键代码如下:
```java
ActivityClientRecord r = mActivities.get(token);
// ...略
mInstrumentation.callActivityOnDestroy(r.activity);
```
这里通过`mActivities`拿到了一个ActivityClientRecord,然后直接把这个record里面的Activity交给Instrument类完成了onDestroy的调用。
在我们这个demo的场景下,r.activity是TargetActivity还是StubActivity?按理说,由于我们欺骗了`AMS`,`AMS`应该只知道`StubActivity`的存在,它压根儿就不知道TargetActivity是什么,为什么它能正确完成对TargetActivity生命周期的回调呢?
一切的秘密在`token`里面。`AMS`与`ActivityThread`之间对于Activity的生命周期的交互,并没有直接使用Activity对象进行交互,而是使用一个token来标识,这个token是binder对象,因此可以方便地跨进程传递。Activity里面有一个成员变量`mToken`代表的就是它,token可以唯一地标识一个Activity对象,它在Activity的`attach`方法里面初始化;
在`AMS`处理Activity的任务栈的时候,使用这个token标记Activity,因此在我们的demo里面,`AMS`进程里面的token对应的是StubActivity,也就是`AMS`还在傻乎乎地操作StubActivity(关于这一点,你可以dump出任务栈的信息,可以观察到dump出的确实是StubActivity)。但是在我们App进程里面,token对应的却是TargetActivity!因此,在ActivityThread执行回调的时候,能正确地回调到TargetActivity相应的方法。
为什么App进程里面,token对应的是TargetActivity呢?
回到代码,ActivityClientRecord是在`mActivities`里面取出来的,确实是根据token取;那么这个token是什么时候添加进去的呢?我们看performLaunchActivity就完成明白了:它通过classloader加载了TargetActivity,然后完成一切操作之后把这个activity添加进了`mActivities`!另外,在这个方法里面我们还能看到对Ativity`attach`方法的调用,它传递给了新创建的Activity一个token对象,而这个token是在ActivityClientRecord构造函数里面初始化的。
至此我们已经可以确认,通过这种方式启动的Activity有它自己完整而独立的生命周期!
## 小节
本文讲述了『启动一个并没有在AndroidManifest.xml中显示声明的Activity』的解决办法,我们成功地绕过了Android的这个限制,这个是插件Activity管理技术的基础;但是要做到启动一个插件Activity问题远没有这么简单。
首先,在Android中,Activity有不同的启动模式;我们声明了一个替身StubActivity,肯定没有满足所有的要求;因此,我们需要在AndroidManifest.xml中声明一系列的有不同launchMode的Activity,还需要完成替身与真正Activity launchMode的匹配过程;这样才能完成启动各种类型Activity的需求,关于这一点,在 DroidPlugin 的com.morgoo.droidplugin.stub包下面可以找到。
另外,每启动一个插件的Activity都需要一个StubActivity,但是AndroidManifest.xml中肯定只能声明有限个,如果一直`startActivity`而不finish的话,那么理论上就需要无限个StubActivity;这个问题该如何解决呢?事实上,这个问题在技术上没有好的解决办法。但是,如果你的App startActivity了十几次,而没有finish任何一个Activity,这样在Activity的回退栈里面有十几个Activity,用户难道按back十几次回到主页吗?有这种需求说明你的产品设计有问题;一个App一级页面,二级页面..到五六级的页面已经影响体验了,所以,每种LauchMode声明十个StubActivity绝对能满足需求了。
最后,在本文所述例子中,TargetActivity与StubActivity存在于同一个Apk,因此系统的ClassLoader能够成功加载并创建TargetActivity的实例。但是在实际的插件系统中,要启动的目标Activity肯定存在于一个单独的文件中,系统默认的ClassLoader无法加载插件中的Activity类——系统压根儿就不知道要加载的插件在哪,谈何加载?因此还有一个很重要的问题需要处理:
**我们要完成插件系统中类的加载**,这可以通过自定义ClassLoader实现。解决了『启动没有在AndroidManifest.xml中显式声明的,并且存在于外部文件中的Activity』的问题,插件系统对于Activity的管理才算得上是一个完全体。篇幅所限,欲知后事如何,请听下回分解!
[1]: 概述.md
[2]: https://github.com/tiann/understand-plugin-framework
[3]: Hook机制之代理Hook.md
[4]: Hook机制之Binder-Hook.md
[5]: Hook机制之AMS&PMS.md
[6]: http://blog.csdn.net/luoshengyang/article/details/6685853
================================================
FILE: DOC/tianweishu/BroadcastReceiver插件化.md
================================================
# BroadcastReceiver插件化
在[Activity生命周期管理][1] 以及 [插件加载机制][2] 中我们详细讲述了插件化过程中对于Activity组件的处理方式,为了实现Activity的插件化我们付出了相当多的努力;那么Android系统的其他组件,比如BroadcastReceiver,Service还有ContentProvider,它们又该如何处理呢?
相比Activity,BroadcastReceiver要简单很多——广播的生命周期相当简单;如果希望插件能够支持广播,这意味着什么?
回想一下我们日常开发的时候是如何使用BroadcastReceiver的:**注册**, **发送**和**接收**;因此,要实现BroadcastReceiver的插件化就这三种操作提供支持;接下来我们将一步步完成这个过程。
阅读本文之前,可以先clone一份 [understand-plugin-framework][5],参考此项目的`receiver-management` 模块。另外,插件框架原理解析系列文章见[索引][6]。
<!-- more -->
如果连BroadcastReceiver的工作原理都不清楚,又怎么能让插件支持它?老规矩,知己知彼。
## 源码分析
我们可以注册一个BroadcastReceiver然后接收我们感兴趣的广播,也可以给某有缘人发出某个广播;因此,我们对源码的分析按照两条路线展开:
### 注册过程
不论是静态广播还是动态广播,在使用之前都是需要注册的;动态广播的注册需要借助Context类的registerReceiver方法,而静态广播的注册直接在AndroidManifest.xml中声明即可;我们首先分析一下动态广播的注册过程。
Context类的registerReceiver的真正实现在ContextImpl里面,而这个方法间接调用了registerReceiverInternal,源码如下:
```java
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null; // Important !!!!!
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
return null;
}
}
```
可以看到,BroadcastReceiver的注册也是通过`AMS`完成的;在进入`AMS`跟踪它的registerReceiver方法之前,我们先弄清楚这个`IIntentReceiver`类型的变量`rd`是什么。首先查阅API文档,很遗憾SDK里面没有导出这个类,我们直接去 [grepcode][3] 上看,文档如下:
> System private API for dispatching intent broadcasts. This is given to the activity manager as part of registering for an intent broadcasts, and is called when it receives intents.
这个类是通过AIDL工具生成的,它是一个Binder对象,因此可以用来跨进程传输;文档说的很清楚,它是用来进行广播分发的。什么意思呢?
由于广播的分发过程是在AMS中进行的,而AMS所在的进程和BroadcastReceiver所在的进程不一样,因此要把广播分发到BroadcastReceiver具体的进程需要进行跨进程通信,这个**通信的载体**就是IIntentReceiver类。其实这个类的作用跟 [Activity生命周期管理][4] 中提到的 `IApplicationThread`相同,都是App进程给AMS进程用来进行通信的对象。另外,`IIntentReceiver`是一个接口,从上述代码中可以看出,它的实现类为LoadedApk.ReceiverDispatcher。
OK,我们继续跟踪源码,AMS类的registerReceiver方法代码有点多,这里不一一解释了,感兴趣的话可以自行查阅;这个方法主要做了以下两件事:
1. 对发送者的身份和权限做出一定的校检
2. 把这个BroadcastReceiver以BroadcastFilter的形式存储在AMS的`mReceiverResolver`变量中,供后续使用。
就这样,被传递过来的BroadcastReceiver已经成功地注册在系统之中,能够接收特定类型的广播了;那么注册在AndroidManifest.xml中的静态广播是如何被系统感知的呢?
在 [插件加载机制][2] 中我们知道系统会通过PackageParser解析Apk中的AndroidManifest.xml文件,因此我们有理由认为,系统会在解析AndroidMafest.xml的<receiver>标签(也即静态注册的广播)的时候保存相应的信息;而Apk的解析过程是在PMS中进行的,因此**静态注册广播的信息存储在PMS中**。接下来的分析会证实这一结论。
### 发送和接收过程
#### 发送过程
发送广播很简单,就是一句context.sendBroadcast(),我们顺藤摸瓜,跟踪这个方法。前文也提到过,Context中方法的调用都会委托到ContextImpl这个类,我们直接看ContextImpl对这个方法的实现:
```java
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
}
```
嗯,发送广播也是通过AMS进行的,我们直接查看ActivityManagerService类的broadcastIntent方法,这个方法仅仅是调用了broadcastIntentLocked方法,我们继续跟踪;broadcastIntentLocked这个方法相当长,处理了诸如粘性广播,顺序广播,各种Flag以及动态广播静态广播的接收过程,这些我们暂时不关心;值得注意的是,在这个方法中我们发现,其实**广播的发送和接收是融为一体的**。某个广播被发送之后,AMS会找出所有注册过的BroadcastReceiver中与这个广播匹配的接收者,然后将这个广播分发给相应的接收者处理。
#### 匹配过程
某一条广播被发出之后,并不是阿猫阿狗都能接收它并处理的;BroadcastReceiver可能只对某些类型的广播感兴趣,因此它也只能接收和处理这种特定类型的广播;在broadcastIntentLocked方法内部有如下代码:
```java
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
== 0) {
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) {
if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
// Query one target user at a time, excluding shell-restricted users
// 略
} else {
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false, userId);
}
}
```
这里有两个列表`receivers`和`registeredReceivers`,看名字好像是广播接收者的列表;下面是它们的赋值过程:
```java
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId);
```
读者可以自行跟踪这两个方法的代码,过程比较简单,我这里直接给出结论:
1. `receivers`是对这个广播感兴趣的**静态BroadcastReceiver**列表;collectReceiverComponents 通过PackageManager获取了与这个广播匹配的静态BroadcastReceiver信息;这里也证实了我们在分析BroadcasrReceiver注册过程中的推论——静态BroadcastReceiver的注册过程的确实在PMS中进行的。
2. `mReceiverResolver`存储了**动态注册**的BroadcastReceiver的信息;还记得这个`mReceiverResolver`吗?我们在分析动态广播的注册过程中发现,动态注册的BroadcastReceiver的相关信息最终存储在此对象之中;在这里,通过mReceiverResolver对象匹配出了对应的BroadcastReceiver供进一步使用。
现在系统通过PMS拿到了所有符合要求的静态BroadcastReceiver,然后从AMS中获取了符合要求的动态BroadcastReceiver;因此接下来的工作非常简单:唤醒这些广播接受者。简单来说就是回调它们的`onReceive`方法。
#### 接收过程
通过上文的分析过程我们知道,在AMS的broadcastIntentLocked方法中找出了符合要求的所有BroadcastReceiver;接下来就需要把这个广播分发到这些接收者之中。在broadcastIntentLocked方法的后半部分有如下代码:
```java
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId);
boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
if (!replaced) {
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
```
首先创建了一个BroadcastRecord代表此次发送的这条广播,然后把它丢进一个队列,最后通过scheduleBroadcastsLocked通知队列对广播进行处理。
在BroadcastQueue中通过Handle调度了对于广播处理的消息,调度过程由processNextBroadcast方法完成,而这个方法通过performReceiveLocked最终调用了IIntentReceiver的performReceive方法。
这个`IIntentReceiver`正是在广播注册过程中由App进程提供给AMS进程的Binder对象,现在AMS通过这个Binder对象进行IPC调用通知广播接受者所在进程完成余下操作。在上文我们分析广播的注册过程中提到过,这个IItentReceiver的实现是LoadedApk.ReceiverDispatcher;我们查看这个对象的performReceive方法,源码如下:
```java
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
if (!mActivityThread.post(args)) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
args.sendFinished(mgr);
}
}
}
```
这个方法创建了一个`Args`对象,然后把它post到了mActivityThread这个Handler中;我们查看`Args`类的`run`方法:(坚持一下,马上就分析完了 ^ ^)
```java
public void run() {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
final IActivityManager mgr = ActivityManagerNative.getDefault();
final Intent intent = mCurIntent;
mCurIntent = null;
if (receiver == null || mForgotten) {
if (mRegistered && ordered) {
sendFinished(mgr);
}
return;
}
try {
ClassLoader cl = mReceiver.getClass().getClassLoader(); // Important!! load class
intent.setExtrasClassLoader(cl);
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent); // callback
} catch (Exception e) {
if (mRegistered && ordered) {
sendFinished(mgr);
}
if (mInstrumentation == null ||
!mInstrumentation.onException(mReceiver, e)) {
throw new RuntimeException(
"Error receiving broadcast " + intent
+ " in " + mReceiver, e);
}
}
if (receiver.getPendingResult() != null) {
finish();
}
}
```
这里,我们看到了相应BroadcastReceiver的`onReceive`回调;因此,广播的工作原理到这里就水落石出了;我们接下来将探讨如何实现对于广播的插件化。
## 思路分析
上文中我们分析了BroadcastReceiver的工作原理,那么怎么才能实现对BroadcastReceiver的插件化呢?
从分析过程中我们发现,Framework对于静态广播和动态广播的处理是不同的;不过,这个不同之处仅仅体现在**注册过程**——静态广播需要在AndroidManifest.xml中注册,并且注册的信息存储在PMS中;动态广播不需要预注册,注册的信息存储在AMS中。
从实现Activity的插件化过程中我们知道,需要在AndroidManifest.xml中预先注册是一个相当麻烦的事情——我们需要使用『替身』并在合适的时候进行『偷梁换柱』;因此看起来动态广播的处理要容易那么一点,我们先讨论一下如何实现动态注册BroadcastReceiver的插件化。
首先,广播并没有复杂的生命周期,它的整个存活过程其实就是一个`onReceive`回调;而动态广播又不需要在AndroidManifest.xml中预先注册,所以动态注册的BroadcastReceiver其实可以当作一个普通的Java对象;我们完全可以用纯ClassLoader技术实现它——不就是把插件中的Receiver加载进来,然后想办法让它能接受`onReceive`回调嘛。
静态BroadcastReceiver看起来要复杂一些,但是我们连Activity都搞定了,还有什么难得到我们呢?对于实现静态BroadcastReceiver插件化的问题,有的童鞋或许会想,我们可以借鉴Activity的工作方式——用替身和Hook解决。但是很遗憾,这样是行不通的。为什么呢?
BroadcastReceiver有一个IntentFilter的概念,也就是说,每一个BroadcastReceiver只对特定的Broadcast感兴趣;而且,AMS在进行广播分发的时候,也会对这些BroadcastReceiver与发出的广播进行匹配,只有Intent匹配的Receiver才能收到广播;在分析源码的时候也提到了这个匹配过程。如果我们尝试用替身Receiver解决静态注册的问题,那么它的IntentFilter该写什么?我们无法预料插件中静态注册的Receiver会使用什么类型的IntentFilter,就算我们在AndroidManifest.xml中声明替身也没有用——我们压根儿收不到与我们的IntentFilter不匹配的广播。其实,我们对于Activity的处理方式也有这个问题;如果你尝试用IntentFilter的方式启动Activity,这并不能成功;这算得上是DroidPlugin的缺陷之一。
那么,我们就真的对静态BroadcastReceiver无能为力吗?想一想这里的难点是什么?
没错,主要是在静态BroadcastReceiver里面这个IntentFilter我们事先无法确定,它是动态变化的;但是,动态BroadcastReceiver不是可以动态添加IntentFilter吗!!!
**可以把静态广播当作动态广播处理**
既然都是广播,它们的功能都是订阅一个特定的消息然后执行某个特定的操作,我们完全可以把插件中的静态广播全部注册为动态广播,这样就解决了静态广播的问题。当然,这样也是有缺陷的,静态BroadcastReceiver与动态BroadcastReceiver一个非常大的不同之处在于:动态BroadcastReceiver在进程死亡之后是无法接收广播的,而静态BroadcastReceiver则可以——系统会唤醒Receiver所在进程;这算得上缺陷之二,当然,瑕不掩瑜。
## 静态广播非静态的实现
上文我们提到,可以把静态BroadcastReceiver当作动态BroadcastReceiver处理;我们接下来实现这个过程。
### 解析
要把插件中的静态BroadcastReceiver当作动态BroadcastReceiver处理,我们首先得知道插件中到底注册了哪些广播;这个过程归根结底就是获取AndroidManifest.xml中的<receiver>标签下面的内容,我们可以选择手动解析xml文件;这里我们选择使用系统的 PackageParser 帮助解析,这种方式在之前的 [插件加载过程][] 中也用到过,如果忘记了可以温习一下。
PackageParser中有一系列方法用来提取Apk中的信息,可是翻遍了这个类也没有找到与「Receiver」名字相关的方法;最终我们发现BroadcastReceiver信息是用与Activity相同的类存储的!这一点可以在PackageParser的内部类Package中发现端倪——成员变量`receivers`和`activities`的范型类型相同。所以,我们要解析apk的<receiver>的信息,可以使用PackageParser的`generateActivityInfo`方法。
知道这一点之后,代码就比较简单了;使用反射调用相应的隐藏接口,并且在必要的时候构造相应参数的方式我们在插件化系列文章中已经讲述过很多,相信读者已经熟练,这里就不赘述,直接贴代码:
```java
private static void parserReceivers(File apkFile) throws Exception {
Class<?> packageParserClass = Class.forName("android.content.pm.PackageParser");
Method parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage", File.class, int.class);
Object packageParser = packageParserClass.newInstance();
// 首先调用parsePackage获取到apk对象对应的Package对象
Object packageObj = parsePackageMethod.invoke(packageParser, apkFile, PackageManager.GET_RECEIVERS);
// 读取Package对象里面的receivers字段,注意这是一个 List<Activity> (没错,底层把<receiver>当作<activity>处理)
// 接下来要做的就是根据这个List<Activity> 获取到Receiver对应的 ActivityInfo (依然是把receiver信息用activity处理了)
Field receiversField = packageObj.getClass().getDeclaredField("receivers");
List receivers = (List) receiversField.get(packageObj);
// 调用generateActivityInfo 方法, 把PackageParser.Activity 转换成
Class<?> packageParser$ActivityClass = Class.forName("android.content.pm.PackageParser$Activity");
Class<?> packageUserStateClass = Class.forName("android.content.pm.PackageUserState");
Class<?> userHandler = Class.forName("android.os.UserHandle");
Method getCallingUserIdMethod = userHandler.getDeclaredMethod("getCallingUserId");
int userId = (Integer) getCallingUserIdMethod.invoke(null);
Object defaultUserState = packageUserStateClass.newInstance();
Class<?> componentClass = Class.forName("android.content.pm.PackageParser$Component");
Field intentsField = componentClass.getDeclaredField("intents");
// 需要调用 android.content.pm.PackageParser#generateActivityInfo(android.content.pm.ActivityInfo, int, android.content.pm.PackageUserState, int)
Method generateReceiverInfo = packageParserClass.getDeclaredMethod("generateActivityInfo",
packageParser$ActivityClass, int.class, packageUserStateClass, int.class);
// 解析出 receiver以及对应的 intentFilter
for (Object receiver : receivers) {
ActivityInfo info = (ActivityInfo) generateReceiverInfo.invoke(packageParser, receiver, 0, defaultUserState, userId);
List<? extends IntentFilter> filters = (List<? extends IntentFilter>) intentsField.get(receiver);
sCache.put(info, filters);
}
}
```
### 注册
我们已经解析得到了插件中静态注册的BroadcastReceiver的信息,现在我们只需要把这些静态广播动态注册一遍就可以了;但是,由于BroadcastReceiver的实现类存在于插件之后,我们需要手动用ClassLoader来加载它;这一点在 [插件加载机制][2] 已有讲述,不啰嗦了。
```java
ClassLoader cl = null;
for (ActivityInfo activityInfo : ReceiverHelper.sCache.keySet()) {
Log.i(TAG, "preload receiver:" + activityInfo.name);
List<? extends IntentFilter> intentFilters = ReceiverHelper.sCache.get(activityInfo);
if (cl == null) {
cl = CustomClassLoader.getPluginClassLoader(apk, activityInfo.packageName);
}
// 把解析出来的每一个静态Receiver都注册为动态的
for (IntentFilter intentFilter : intentFilters) {
BroadcastReceiver receiver = (BroadcastReceiver) cl.loadClass(activityInfo.name).newInstance();
context.registerReceiver(receiver, intentFilter);
}
}
```
就这样,我们对插件静态BroadcastReceiver的支持已经完成了,是不是相当简单?至于插件中的动态广播如何实现插件化,这一点**交给读者自行完成**,希望你在解决这个问题的过程中能够加深对于插件方案的理解 ^ ^
## 小节
本文我们介绍了BroadcastReceiver组件的插件化方式,可以看到,插件方案对于BroadcastReceiver的处理相对简单;同时「静态广播非静态」的特性以及BroadcastReceiver先天的一些特点导致插件方案没有办法做到尽善尽美,不过这都是大醇小疵——在绝大多数情况下,这样的处理方式是可以满足需求的。
虽然对于BroadcastReceiver的处理方式相对简单,但是文章的内容却并不短——我们花了大量的篇幅讲述BroadcastReceiver的原理,这也是我的初衷:借助DroidPlugin更深入地了解Android Framework。
[1]: Activity生命周期管理.md
[2]: ClassLoader管理.md
[3]: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.1_r1/android/content/IIntentReceiver.java?av=f
[4]: Activity生命周期管理.md
[5]: https://github.com/tiann/understand-plugin-framework
[6]: 概述.md
================================================
FILE: DOC/tianweishu/ClassLoader管理.md
================================================
# 插件加载机制
上文 [Activity生命周期管理][3] 中我们地完成了『启动没有在AndroidManifest.xml中显式声明的Activity』的任务;通过Hook `AMS`和拦截ActivityThread中`H`类对于组件调度我们成功地绕过了AndroidMAnifest.xml的限制。
但是我们启动的『没有在AndroidManifet.xml中显式声明』的Activity和宿主程序存在于同一个Apk中;通常情况下,插件均以独立的文件存在甚至通过网络获取,这时候插件中的Activity能否成功启动呢?
要启动Activity组件肯定先要创建对应的Activity类的对象,从上文 [Activity生命周期管理][3] 知道,创建Activity类对象的过程如下:
```java
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
```
也就是说,系统通过`ClassLoader`加载了需要的Activity类并通过反射调用构造函数创建出了Activity对象。如果Activity组件存在于独立于宿主程序的文件之中,系统的ClassLoader怎么知道去哪里加载呢?因此,如果不做额外的处理,插件中的Activity对象甚至都没有办法创建出来,谈何启动?
因此,要使存在于独立文件或者网络中的插件被成功启动,首先就需要解决这个**插件类加载**的问题。
下文将围绕此问题展开,完成『启动没有在AndroidManifest.xml中显示声明,并且存在于外部插件中的Activity』的任务。
阅读本文之前,可以先clone一份 [understand-plugin-framework][2],参考此项目的`classloader-hook` 模块。另外,插件框架原理解析系列文章见[索引][1]。
<!-- more -->
## ClassLoader机制
或许有的童鞋还不太了解Java的ClassLoader机制,我这里简要介绍一下。
> Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校检、转换解析和初始化的,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
> 与那些在编译时进行链连接工作的语言不同,在Java语言里面,类型的加载、连接和初始化都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增加一些性能开销,但是会为Java应用程序提供高度的灵活性,Java里天生可以同代拓展的语言特性就是依赖运行期动态加载和动态链接这个特点实现的。例如,如果编写一个面相接口的应用程序,可以等到运行时在制定实际的实现类;用户可以通过Java与定义的和自定义的类加载器,让一个本地的应用程序可以在运行时从网络或其他地方加载一个二进制流作为代码的一部分,这种组装应用程序的方式目前已经广泛应用于Java程序之中。从最基础的Applet,JSP到复杂的OSGi技术,都使用了Java语言运行期类加载的特性。
Java的类加载是一个相对复杂的过程;它包括加载、验证、准备、解析和初始化五个阶段;对于开发者来说,可控性最强的是**加载阶段**;加载阶段主要完成三件事:
1. 根据一个类的全限定名来获取定义此类的二进制字节流
2. 将这个字节流所代表的静态存储结构转化为JVM方法区中的运行时数据结构
3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
『通过一个类的全限定名获取描述此类的二进制字节流』这个过程被抽象出来,就是Java的类加载器模块,也即JDK中ClassLoader API。
Android Framework提供了DexClassLoader这个类,简化了『通过一个类的全限定名获取描述次类的二进制字节流』这个过程;我们只需要告诉DexClassLoader一个dex文件或者apk文件的路径就能完成类的加载。因此本文的内容用一句话就可以概括:
**将插件的dex或者apk文件告诉『合适的』DexClassLoader,借助它完成插件类的加载**
关于CLassLoader机制更多的内容,请参阅『深入理解Java虚拟机』这本书。
## 思路分析
Android系统使用了ClassLoader机制来进行Activity等组件的加载;apk被安装之后,APK文件的代码以及资源会被系统存放在固定的目录(比如/data/app/package_name/base-1.apk )系统在进行类加载的时候,会自动去这一个或者几个特定的路径来寻找这个类;但是系统并不知道存在于插件中的Activity组件的信息(插件可以是任意位置,甚至是网络,系统无法提前预知),因此正常情况下系统无法加载我们插件中的类;因此也没有办法创建Activity的对象,更不用谈启动组件了。
解决这个问题有两个思路,要么全盘接管这个类加载的过程;要么告知系统我们使用的插件存在于哪里,让系统帮忙加载;这两种方式或多或少都需要**干预**这个类加载的过程。老规矩,知己知彼,百战不殆。我们首先分析一下,系统是如果完成这个类加载过程的。
我们再次搬出Activity的创建过程的代码:
```java
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
```
这里可以很明显地看到,系统通过待启动的Activity的类名`className`,然后使用ClassLoader对象`cl`把这个类加载进虚拟机,最后使用反射创建了这个Activity类的实例对象。要想干预这个ClassLoader(告知它我们的路径或者替换他),我们首先得看看这玩意到底是个什么来头。(从哪里创建的)
`cl`这个ClasssLoader对象通过`r.packageInfo`对象的getClassLoader()方法得到,r.packageInfo是一个LoadedApk类的对象;那么,LoadedApk到底是个什么东西??
我们查阅LoadedApk类的文档,只有一句话,不过说的很明白:
> Local state maintained about a currently loaded .apk.
**LoadedApk对象是APK文件在内存中的表示。** Apk文件的相关信息,诸如Apk文件的代码和资源,甚至代码里面的Activity,Service等组件的信息我们都可以通过此对象获取。
OK, 我们知道这个LoadedApk是何方神圣了;接下来我们要搞清楚的是:这个 `r.packageInfo` 到底是从哪里获取的?
我们顺着 performLaunchActivity上溯,辗转handleLaunchActivity回到了 `H` 类的LAUNCH_ACTIVITY消息,找到了`r.packageInfo`的来源:
```java
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
```
getPackageInfoNoCheck方法很简单,直接调用了getPackageInfo方法:
```java
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
CompatibilityInfo compatInfo) {
return getPackageInfo(ai, compatInfo, null, false, true, false);
}
```
在这个getPackageInfo方法里面我们发现了端倪:
```java
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
boolean registerPackage) {
// 获取userid信息
final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
synchronized (mResourcesManager) {
// 尝试获取缓存信息
WeakReference<LoadedApk> ref;
if (differentUser) {
// Caching not supported across users
ref = null;
} else if (includeCode) {
ref = mPackages.get(aInfo.packageName);
} else {
ref = mResourcePackages.get(aInfo.packageName);
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
if (packageInfo == null || (packageInfo.mResources != null
&& !packageInfo.mResources.getAssets().isUpToDate())) {
// 缓存没有命中,直接new
packageInfo =
new LoadedApk(this, aInfo, compatInfo, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
// 省略。。更新缓存
return packageInfo;
}
}
```
这个方法很重要,我们必须弄清楚每一步;
首先,它判断了调用方和或许App信息的一方是不是同一个userId;如果是同一个user,那么可以共享缓存数据(要么缓存的代码数据,要么缓存的资源数据)
接下来尝试获取缓存数据;如果没有命中缓存数据,才通过LoadedApk的构造函数创建了LoadedApk对象;创建成功之后,如果是同一个uid还放入了缓存。
提到缓存数据,看过[Hook机制之Binder Hook][7]的童鞋可能就知道了,我们之前成功借助ServiceManager的本地代理使用缓存的机制Hook了各种Binder;因此这里完全可以如法炮制——我们拿到这一份缓存数据,修改里面的ClassLoader;自己控制类加载的过程,这样加载插件中的Activity类的问题就解决了。这就引出了我们加载插件类的第一种方案:
## 激进方案:Hook掉ClassLoader,自己操刀
从上述分析中我们得知,在获取LoadedApk的过程中使用了一份缓存数据;这个缓存数据是一个`Map`,从包名到LoadedApk的一个映射。正常情况下,我们的插件肯定不会存在于这个对象里面;但是**如果我们手动把我们插件的信息添加到里面呢?**系统在查找缓存的过程中,会直接命中缓存!进而使用我们添加进去的LoadedApk的ClassLoader来加载这个特定的Activity类!这样我们就能接管我们自己插件类的加载过程了!
<!--但是,细心的读者可能会发现;缓存命中还有一个条件——UID相同,因此我们需要**共享UID**-->
这个缓存对象`mPackages`存在于ActivityThread类中;老方法,我们首先获取这个对象:
```java
// 先获取到当前的ActivityThread对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
// 获取到 mPackages 这个静态成员变量, 这里缓存了dex包的信息
Field mPackagesField = activityThreadClass.getDeclaredField("mPackages");
mPackagesField.setAccessible(true);
Map mPackages = (Map) mPackagesField.get(currentActivityThread);
```
拿到这个Map之后接下来怎么办呢?**我们需要填充这个map,把插件的信息塞进这个map里面**,以便系统在查找的时候能命中缓存。但是这个填充这个Map我们出了需要包名之外,还需要一个LoadedApk对象;如何创建一个LoadedApk对象呢?
我们当然可以直接反射调用它的构造函数直接创建出需要的对象,但是万一哪里有疏漏,构造参数填错了怎么办?又或者Android的不同版本使用了不同的参数,导致我们创建出来的对象与系统创建出的对象不一致,无法work怎么办?
因此我们需要使用与系统完全相同的方式创建LoadedApk对象;从上文分析得知,系统创建LoadedApk对象是通过`getPackageInfo`来完成的,因此我们可以调用这个函数来创建LoadedApk对象;但是这个函数是`private`的,我们无法使用。
有的童鞋可能会有疑问了,`private`不是也能反射到吗?我们确实能够调用这个函数,但是`private`表明这个函数是内部实现,或许那一天Google高兴,把这个函数改个名字我们就直接GG了;但是public函数不同,public被导出的函数你无法保证是否有别人调用它,因此大部分情况下不会修改;我们最好调用public函数来保证尽可能少的遇到兼容性问题。(当然,如果实在木有路可以考虑调用私有方法,自己处理兼容性问题,这个我们以后也会遇到)
间接调用`getPackageInfo`这个私有函数的public函数有同名的getPackageInfo系列和getPackageInfoNoCheck;简单查看源代码发现,getPackageInfo除了获取包的信息,还检查了包的一些组件;为了绕过这些验证,我们选择使用`getPackageInfoNoCheck`获取LoadedApk信息。
### 构建插件LoadedApk对象
我们这一步的目的很明确,通过getPackageInfoNoCheck函数创建出我们需要的LoadedApk对象,以供接下来使用。
这个函数的签名如下:
```java
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
CompatibilityInfo compatInfo) {
```
因此,为了调用这个函数,我们需要构造两个参数。其一是ApplicationInfo,其二是CompatibilityInfo;第二个参数顾名思义,代表这个App的兼容性信息,比如targetSDK版本等等,这里我们只需要提取出app的信息,因此直接使用默认的兼容性即可;在CompatibilityInfo类里面有一个公有字段DEFAULT_COMPATIBILITY_INFO代表默认兼容性信息;因此,我们的首要目标是获取这个ApplicationInfo信息。
### 构建插件ApplicationInfo信息
我们首先看看ApplicationInfo代表什么,这个类的文档说的很清楚:
> Information you can retrieve about a particular application. This corresponds to information collected from the AndroidManifest.xml's <application> tag.
也就是说,这个类就是AndroidManifest.xml里面的<application> 这个标签下面的信息;这个AndroidManifest.xml无疑是一个标准的xml文件,因此我们完全可以自己使用parse来解析这个信息。
那么,系统是如何获取这个信息的呢?其实Framework就有一个这样的parser,也即PackageParser;理论上,我们也可以借用系统的parser来解析AndroidMAnifest.xml从而得到ApplicationInfo的信息。但遗憾的是,**这个类的兼容性很差**;Google几乎在每一个Android版本都对这个类动刀子,如果坚持使用系统的解析方式,必须写一系列兼容行代码!!DroidPlugin就选择了这种方式,相关类如下:
<img src="http://7xp3xc.com1.z0.glb.clouddn.com/201601/1459829051777.png" width="283" alt="DroidPlugin的PackageParser"/>
看到这里我就问你怕不怕!!!这也是我们之前提到的**私有或者隐藏的API可以使用,但必须处理好兼容性问题**;如果Android 7.0发布,这里估计得添加一个新的类PackageParseApi24。
我这里使用API 23作为演示,**版本不同的可能无法运行**请自行查阅 DroidPlugin 不同版本如何处理。
OK回到正题,我们决定使用PackageParser类来提取ApplicationInfo信息。下图是API 23上,PackageParser的部分类结构图:
<img src="http://7xp3xc.com1.z0.glb.clouddn.com/201601/1459829674687.png" width="481"/>
看起来有我们需要的方法 generateApplication;确实如此,依靠这个方法我们可以成功地拿到ApplicationInfo。
由于PackageParser是@hide的,因此我们需要通过反射进行调用。我们根据这个generateApplicationInfo方法的签名:
```java
public static ApplicationInfo generateApplicationInfo(Package p, int flags,
PackageUserState state)
```
可以写出调用generateApplicationInfo的反射代码:
```java
Class<?> packageParserClass = Class.forName("android.content.pm.PackageParser");
// 首先拿到我们得终极目标: generateApplicationInfo方法
// API 23 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// public static ApplicationInfo generateApplicationInfo(Package p, int flags,
// PackageUserState state) {
// 其他Android版本不保证也是如此.
Class<?> packageParser$PackageClass = Class.forName("android.content.pm.PackageParser$Package");
Class<?> packageUserStateClass = Class.forName("android.content.pm.PackageUserState");
Method generateApplicationInfoMethod = packageParserClass.getDeclaredMethod("generateApplicationInfo",
packageParser$PackageClass,
int.class,
packageUserStateClass);
```
要成功调用这个方法,还需要三个参数;因此接下来我们需要一步一步构建调用此函数的参数信息。
#### 构建PackageParser.Package
generateApplicationInfo方法需要的第一个参数是PackageParser.Package;从名字上看这个类代表某个apk包的信息,我们看看文档怎么解释:
> Representation of a full package parsed from APK files on disk. A package consists of a single base APK, and zero or more split APKs.
果然,这个类代表从PackageParser中解析得到的某个apk包的信息,是磁盘上apk文件在内存中的数据结构表示;因此,要获取这个类,肯定需要解析整个apk文件。PackageParser中解析apk的核心方法是parsePackage,这个方法返回的就是一个Package类型的实例,因此我们调用这个方法即可;使用反射代码如下:
```java
// 首先, 我们得创建出一个Package对象出来供这个方法调用
// 而这个需要得对象可以通过 android.content.pm.PackageParser#parsePackage 这个方法返回得 Package对象得字段获取得到
// 创建出一个PackageParser对象供使用
Object packageParser = packageParserClass.newInstance();
// 调用 PackageParser.parsePackage 解析apk的信息
Method parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage", File.class, int.class);
// 实际上是一个 android.content.pm.PackageParser.Package 对象
Object packageObj = parsePackageMethod.invoke(packageParser, apkFile, 0);
```
这样,我们就得到了generateApplicationInfo的第一个参数;第二个参数是解析包使用的flag,我们直接选择解析全部信息,也就是0;
#### 构建PackageUserState
第三个参数是PackageUserState,代表不同用户中包的信息。由于Android是一个多任务多用户系统,因此不同的用户同一个包可能有不同的状态;这里我们只需要获取包的信息,因此直接使用默认的即可;
至此,generateApplicaionInfo的参数我们已经全部构造完成,直接调用此方法即可得到我们需要的applicationInfo对象;在返回之前我们需要做一点小小的修改:使用系统系统的这个方法解析得到的ApplicationInfo对象中并没有apk文件本身的信息,所以我们把解析的apk文件的路径设置一下(ClassLoader依赖dex文件以及apk的路径):
```java
// 第三个参数 mDefaultPackageUserState 我们直接使用默认构造函数构造一个出来即可
Object defaultPackageUserState = packageUserStateClass.newInstance();
// 万事具备!!!!!!!!!!!!!!
ApplicationInfo applicationInfo = (ApplicationInfo) generateApplicationInfoMethod.invoke(packageParser,
packageObj, 0, defaultPackageUserState);
String apkPath = apkFile.getPath();
applicationInfo.sourceDir = apkPath;
applicationInfo.publicSourceDir = apkPath;
```
### 替换ClassLoader
#### 获取LoadedApk信息
方才为了获取ApplicationInfo我们费了好大一番精力;回顾一下我们的初衷:
我们最终的目的是调用getPackageInfoNoCheck得到LoadedApk的信息,并替换其中的mClassLoader然后把把添加到ActivityThread的mPackages缓存中;从而达到我们使用自己的ClassLoader加载插件中的类的目的。
现在我们已经拿到了getPackageInfoNoCheck这个方法中至关重要的第一个参数applicationInfo;上文提到第二个参数CompatibilityInfo代表设备兼容性信息,直接使用默认的值即可;因此,两个参数都已经构造出来,我们可以调用getPackageInfoNoCheck获取LoadedApk:
```java
// android.content.res.CompatibilityInfo
Class<?> compatibilityInfoClass = Class.forName("android.content.res.CompatibilityInfo");
Method getPackageInfoNoCheckMethod = activityThreadClass.getDeclaredMethod("getPackageInfoNoCheck", ApplicationInfo.class, compatibilityInfoClass);
Field defaultCompatibilityInfoField = compatibilityInfoClass.getDeclaredField("DEFAULT_COMPATIBILITY_INFO");
defaultCompatibilityInfoField.setAccessible(true);
Object defaultCompatibilityInfo = defaultCompatibilityInfoField.get(null);
ApplicationInfo applicationInfo = generateApplicationInfo(apkFile);
Object loadedApk = getPackageInfoNoCheckMethod.invoke(currentActivityThread, applicationInfo, defaultCompatibilityInfo);
```
我们成功地构造出了LoadedAPK, 接下来我们需要替换其中的ClassLoader,然后把它添加进ActivityThread的mPackages中:
```java
String odexPath = Utils.getPluginOptDexDir(applicationInfo.packageName).getPath();
String libDir = Utils.getPluginLibDir(applicationInfo.packageName).getPath();
ClassLoader classLoader = new CustomClassLoader(apkFile.getPath(), odexPath, libDir, ClassLoader.getSystemClassLoader());
Field mClassLoaderField = loadedApk.getClass().getDeclaredField("mClassLoader");
mClassLoaderField.setAccessible(true);
mClassLoaderField.set(loadedApk, classLoader);
// 由于是弱引用, 因此我们必须在某个地方存一份, 不然容易被GC; 那么就前功尽弃了.
sLoadedApk.put(applicationInfo.packageName, loadedApk);
WeakReference weakReference = new WeakReference(loadedApk);
mPackages.put(applicationInfo.packageName, weakReference);
```
我们的这个CustomClassLoader非常简单,直接继承了DexClassLoader,什么都没有做;当然这里可以直接使用DexClassLoader,这里重新创建一个类是为了更有区分度;以后也可以通过修改这个类实现对于类加载的控制:
```java
public class CustomClassLoader extends DexClassLoader {
public CustomClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {
super(dexPath, optimizedDirectory, libraryPath, parent);
}
}
```
到这里,我们已经成功地把把插件的信息放入ActivityThread中,这样我们插件中的类能够成功地被加载;因此插件中的Activity实例能被成功第创建;由于整个流程较为复杂,我们简单梳理一下:
1. 在ActivityThread接收到IApplication的 scheduleLaunchActivity远程调用之后,将消息转发给`H`
2. `H`类在handleMessage的时候,调用了getPackageInfoNoCheck方法来获取待启动的组件信息。在这个方法中会优先查找`mPackages`中的缓存信息,而我们已经手动把插件信息添加进去;因此能够成功命中缓存,获取到独立存在的插件信息。
3. `H`类然后调用handleLaunchActivity最终转发到performLaunchActivity方法;这个方法使用从getPackageInfoNoCheck中拿到LoadedApk中的mClassLoader来加载Activity类,进而使用反射创建Activity实例;接着创建Application,Context等完成Activity组件的启动。
看起来好像已经天衣无缝万事大吉了;但是运行一下会出现一个异常,如下:
```java
04-05 02:49:53.742 11759-11759/com.weishu.upf.hook_classloader E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.weishu.upf.hook_classloader, PID: 11759
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.weishu.upf.ams_pms_hook.app/com.weishu.upf.ams_pms_hook.app.MainActivity}: java.lang.RuntimeException: Unable to instantiate application android.app.Application: java.lang.IllegalStateException: Unable to get package info for com.weishu.upf.ams_pms_hook.app; is package not installed?
```
错误提示说是无法实例化 `Application`,而Application的创建也是在performLaunchActivity中进行的,这里有些蹊跷,我们仔细查看一下。
#### 绕过系统检查
通过ActivityThread的performLaunchActivity方法可以得知,Application通过LoadedApk的makeApplication方法创建,我们查看这个方法,在源码中发现了上文异常抛出的位置:
```java
try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
initializeJavaContextClassLoader();
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to instantiate application " + appClass
+ ": " + e.toString(), e);
}
}
```
木有办法,我们只有一行一行地查看到底是哪里抛出这个异常的了;所幸代码不多。(所以说,缩小异常范围是一件多么重要的事情!!!)
第一句 getClassLoader() 没什么可疑的,虽然方法很长,但是它木有抛出任何异常(当然,它调用的代码可能抛出异常,万一找不到只能进一步深搜了;所以我觉得这里应该使用受检异常)。
然后我们看第二句,如果包名不是`android`开头,那么调用了一个叫做initializeJavaContextClassLoader的方法;我们查阅这个方法:
```java
private void initializeJavaContextClassLoader() {
IPackageManager pm = ActivityThread.getPackageManager();
android.content.pm.PackageInfo pi;
try {
pi = pm.getPackageInfo(mPackageName, 0, UserHandle.myUserId());
} catch (RemoteException e) {
throw new IllegalStateException("Unable to get package info for "
+ mPackageName + "; is system dying?", e);
}
if (pi == null) {
throw new IllegalStateException("Unable to get package info for "
+ mPackageName + "; is package not installed?");
}
boolean sharedUserIdSet = (pi.sharedUserId != null);
boolean processNameNotDefault =
(pi.applicationInfo != null &&
!mPackageName.equals(pi.applicationInfo.processName));
boolean sharable = (sharedUserIdSet || processNameNotDefault);
ClassLoader contextClassLoader =
(sharable)
? new WarningContextClassLoader()
: mClassLoader;
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
```
这里,我们找出了这个异常的来源:原来这里调用了`getPackageInfo`方法获取包的信息;而我们的插件**并没有安装在系统上**,因此系统肯定认为插件没有安装,这个方法肯定返回null。所以,我们还要欺骗一下PMS,让系统觉得**插件已经安装在系统上了**;至于如何欺骗 PMS,[Hook机制之AMS&PMS][4] 有详细解释,这里直接给出代码,不赘述了:
```java
private static void hookPackageManager() throws Exception {
// 这一步是因为 initializeJavaContextClassLoader 这个方法内部无意中检查了这个包是否在系统安装
// 如果没有安装, 直接抛出异常, 这里需要临时Hook掉 PMS, 绕过这个检查.
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
// 获取ActivityThread里面原始的 sPackageManager
Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
sPackageManagerField.setAccessible(true);
Object sPackageManager = sPackageManagerField.get(currentActivityThread);
// 准备好代理对象, 用来替换原始的对象
Class<?> iPackageManagerInterface = Class.forName("android.content.pm.IPackageManager");
Object proxy = Proxy.newProxyInstance(iPackageManagerInterface.getClassLoader(),
new Class<?>[] { iPackageManagerInterface },
new IPackageManagerHookHandler(sPackageManager));
// 1. 替换掉ActivityThread里面的 sPackageManager 字段
sPackageManagerField.set(currentActivityThread, proxy);
}
```
OK到这里,我们已经能够成功地加载**简单的**独立的存在于外部文件系统中的apk了。至此 关于 DroidPlugin 对于Activity生命周期的管理已经完全讲解完毕了;这是一种极其复杂的Activity管理方案,我们仅仅写一个用来理解的demo就Hook了相当多的东西,在Framework层来回牵扯;这其中的来龙去脉要完全把握清楚还请读者亲自翻阅源码。另外,我在此 对DroidPlugin 作者献上我的膝盖~这其中的玄妙让人叹为观止!
上文给出的方案中,我们全盘接管了插件中类的加载过程,这是一种相对暴力的解决方案;能不能更温柔一点呢?通俗来说,我们可以选择改革,而不是革命——告诉系统ClassLoader一些必要信息,让它帮忙完成插件类的加载。
## 保守方案:委托系统,让系统帮忙加载
我们再次搬出ActivityThread中加载Activity类的代码:
```java
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
```
我们知道 这个r.packageInfo中的`r`是通过getPackageInfoNoCheck获取到的;在『激进方案』中我们把插件apk手动添加进缓存,采用自己加载办法解决;如果我们不干预这个过程,导致无法命中mPackages中的缓存,会发生什么?
查阅 getPackageInfo方法如下:
```java
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
boolean registerPackage) {
final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
if (differentUser) {
// Caching not supported across users
ref = null;
} else if (includeCode) {
ref = mPackages.get(aInfo.packageName);
} else {
ref = mResourcePackages.get(aInfo.packageName);
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
if (packageInfo == null || (packageInfo.mResources != null
&& !packageInfo.mResources.getAssets().isUpToDate())) {
packageInfo =
new LoadedApk(this, aInfo, compatInfo, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
// 略
}
}
```
可以看到,没有命中缓存的情况下,系统直接new了一个LoadedApk;注意这个构造函数的第二个参数`aInfo`,这是一个ApplicationInfo类型的对象。在『激进方案』中我们为了获取独立插件的ApplicationInfo花了不少心思;那么如果不做任何处理这里传入的这个`aInfo`参数是什么?
追本溯源不难发现,这个aInfo是从我们的替身StubActivity中获取的!而StubActivity存在于宿主程序中,所以,这个`aInfo`对象代表的实际上就是宿主程序的Application信息!
我们知道,接下来会使用new出来的这个LoadedApk的getClassLoader()方法获取到ClassLoader来对插件的类进行加载;而获取到的这个ClassLoader是宿主程序使用的ClassLoader,因此现在还无法加载插件的类;那么,**我们能不能让宿主的ClasLoader获得加载插件类的能力呢?**;如果我们告诉宿主使用的ClassLoader插件使用的类在哪里,就能帮助他完成加载!
### 宿主的ClassLoader在哪里,是唯一的吗?
上面说到,我们可以通过告诉宿主程序的ClassLoader插件使用的类,让宿主的ClasLoader完成对于插件类的加载;那么问题来了,我们如何获取到宿主的ClassLoader?宿主程序使用的ClasLoader默认情况下是全局唯一的吗?
答案是肯定的。
因为在FrameWork中宿主程序也是使用LoadedApk表示的,如同Activity启动是加载Activity类一样,宿主中的类也都是通过LoadedApk的getClassLoader()方法得到的ClassLoader加载的;由类加载机制的『双亲委派』特性,只要有一个应用程序类由某一个ClassLoader加载,那么它引用到的别的类除非父加载器能加载,否则都是由这同一个加载器加载的(不遵循双亲委派模型的除外)。
表示宿主的LoadedApk在Application类中有一个成员变量`mLoadedApk`,而这个变量是从ContextImpl中获取的;ContextImpl重写了getClassLoader方法,因此**我们在Context环境中直接getClassLoader()获取到的就是宿主程序唯一的ClassLoader**。
### LoadedApk的ClassLoader到底是什么?
现在我们确保了『使用宿主ClassLoader帮助加载插件类』可行性;那么我们应该如何完成这个过程呢?
知己知彼,百战不殆。
不论是宿主程序还是插件程序都是通过LoadedApk的getClassLoader()方法返回的ClassLoader进行类加载的,返回的这个ClassLoader到底是个什么东西??这个方法源码如下:
```java
public ClassLoader getClassLoader() {
synchronized (this) {
if (mClassLoader != null) {
return mClassLoader;
}
if (mIncludeCode && !mPackageName.equals("android")) {
// 略...
mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib,
mBaseClassLoader);
StrictMode.setThreadPolicy(oldPolicy);
} else {
if (mBaseClassLoader == null) {
mClassLoader = ClassLoader.getSystemClassLoader();
} else {
mClassLoader = mBaseClassLoader;
}
}
return mClassLoader;
}
}
```
可以看到,非`android`开头的包和`android`开头的包分别使用了两种不同的ClassLoader,我们只关心第一种;因此继续跟踪ApplicationLoaders类:
```java
public ClassLoader getClassLoader(String zip, String libPath, ClassLoader parent)
{
ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent();
synchronized (mLoaders) {
if (parent == null) {
parent = baseParent;
}
if (parent == baseParent) {
ClassLoader loader = mLoaders.get(zip);
if (loader != null) {
return loader;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
PathClassLoader pathClassloader =
new PathClassLoader(zip, libPath, parent);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
mLoaders.put(zip, pathClassloader);
return pathClassloader;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
PathClassLoader pathClassloader = new PathClassLoader(zip, parent);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return pathClassloader;
}
}
```
可以看到,应用程序使用的ClassLoader都是PathClassLoader类的实例。那么,这个PathClassLoader是什么呢?从Android SDK给出的源码只能看出这么多:
```java
public class PathClassLoader extends BaseDexClassLoader {
public PathClassLoader(String dexPath, ClassLoader parent) {
super((String)null, (File)null, (String)null, (ClassLoader)null);
throw new RuntimeException("Stub!");
}
public PathClassLoader(String dexPath, String libraryPath, ClassLoader parent) {
super((String)null, (File)null, (String)null, (ClassLoader)null);
throw new RuntimeException("Stub!");
}
}
```
SDK没有导出这个类的源码,我们去[androidxref][5]上面看;发现其实这个类真的就这么多内容;我们继续查看它的父类[BaseDexClassLoader][6];ClassLoader嘛,我们查看findClass或者defineClass方法,BaseDexClassLoader的findClass方法如下:
```java
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
for (Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return c;
}
```
可以看到,查找Class的任务通过`pathList`完成;这个`pathList`是一个`DexPathList`类的对象,它的`findClass`方法如下:
```java
public Class findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
DexFile dex = element.dexFile;
if (dex != null) {
Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
```
这个DexPathList内部有一个叫做dexElements的数组,然后findClass的时候会遍历这个数组来查找Class;**如果我们把插件的信息塞进这个数组里面,那么不就能够完成类的加载过程吗?!!**
### 给默认ClassLoader打补丁
通过上述分析,我们知道,可以把插件的相关信息放入BaseDexClassLoader的表示dex文件的数组里面,这样宿主程序的ClassLoader在进行类加载,遍历这个数组的时候,会自动遍历到我们添加进去的插件信息,从而完成插件类的加载!
接下来,我们实现这个过程;我们会用到一些较为复杂的反射技术哦~不过代码非常短:
```java
public static void patchClassLoader(ClassLoader cl, File apkFile, File optDexFile)
throws IllegalAccessException, NoSuchMethodException, IOException, InvocationTargetException, InstantiationException, NoSuchFieldException {
// 获取 BaseDexClassLoader : pathList
Field pathListField = DexClassLoader.class.getSuperclass().getDeclaredField("pathList");
pathListField.setAccessible(true);
Object pathListObj = pathListField.get(cl);
// 获取 PathList: Element[] dexElements
Field dexElementArray = pathListObj.getClass().getDeclaredField("dexElements");
dexElementArray.setAccessible(true);
Object[] dexElements = (Object[]) dexElementArray.get(pathListObj);
// Element 类型
Class<?> elementClass = dexElements.getClass().getComponentType();
// 创建一个数组, 用来替换原始的数组
Object[] newElements = (Object[]) Array.newInstance(elementClass, dexElements.length + 1);
// 构造插件Element(File file, boolean isDirectory, File zip, DexFile dexFile) 这个构造函数
Constructor<?> constructor = elementClass.getConstructor(File.class, boolean.class, File.class, DexFile.class);
Object o = constructor.newInstance(apkFile, false, apkFile, DexFile.loadDex(apkFile.getCanonicalPath(), optDexFile.getAbsolutePath(), 0));
Object[] toAddElementArray = new Object[] { o };
// 把原始的elements复制进去
System.arraycopy(dexElements, 0, newElements, 0, dexElements.length);
// 插件的那个element复制进去
System.arraycopy(toAddElementArray, 0, newElements, dexElements.length, toAddElementArray.length);
// 替换
dexElementArray.set(pathListObj, newElements);
}
```
短短的二十几行代码,我们就完成了『委托宿主ClassLoader加载插件类』的任务;因此第二种方案也宣告完成!我们简要总结一下这种方式的原理:
1. 默认情况下performLacunchActivity会使用替身StubActivity的ApplicationInfo也就是宿主程序的CLassLoader加载所有的类;我们的思路是告诉宿主ClassLoader我们在哪,让其帮助完成类加载的过程。
2. 宿主程序的ClassLoader最终继承自BaseDexClassLoader,BaseDexClassLoader通过DexPathList进行类的查找过程;而这个查找通过遍历一个dexElements的数组完成;**我们通过把插件dex添加进这个数组**就让宿主ClasLoader获取了加载插件类的能力。
## 小结
本文中我们采用两种方案成功完成了『启动没有在AndroidManifest.xml中显示声明,并且存在于外部插件中的Activity』的任务。
『激进方案』中我们自定义了插件的ClassLoader,并且绕开了Framework的检测;利用ActivityThread对于LoadedApk的缓存机制,我们把携带这个自定义的ClassLoader的插件信息添加进`mPackages`中,进而完成了类的加载过程。
『保守方案』中我们深入探究了系统使用ClassLoader findClass的过程,发现应用程序使用的非系统类都是通过同一个PathClassLoader加载的;而这个类的最终父类BaseDexClassLoader通过DexPathList完成类的查找过程;我们hack了这个查找过程,从而完成了插件类的加载。
这两种方案孰优孰劣呢?
很显然,『激进方案』比较麻烦,从代码量和分析过程就可以看出来,这种机制异常复杂;而且在解析apk的时候我们使用的PackageParser的兼容性非常差,我们不得不手动处理每一个版本的apk解析api;另外,它Hook的地方也有点多:不仅需要Hook AMS和`H`,还需要Hook ActivityThread的`mPackages`和PackageManager!
『保守方案』则简单得多(虽然原理也不简单),不仅代码很少,而且Hook的地方也不多;有一点正本清源的意思,从最最上层Hook住了整个类的加载过程。
但是,我们不能简单地说『保守方案』比『激进方案』好。从根本上说,这两种方案的差异在哪呢?
『激进方案』是**多ClassLoader构架**,每一个插件都有一个自己的ClassLoader,因此类的隔离性非常好——如果不同的插件使用了同一个库的不同版本,它们相安无事!『保守方案』是**单ClassLoader方案**,插件和宿主程序的类全部都通过宿主的ClasLoader加载,虽然代码简单,但是鲁棒性很差;一旦插件之间甚至插件与宿主之间使用的类库有冲突,那么直接GG。
多ClassLoader还有一个优点:可以真正完成代码的热加载!如果插件需要升级,直接重新创建一个自定的ClassLoader加载新的插件,然后替换掉原来的版本即可(Java中,不同ClassLoader加载的同一个类被认为是不同的类);单ClassLoader的话实现非常麻烦,有可能需要重启进程。
在J2EE领域中广泛使用ClasLoader的地方均采用多ClassLoader架构,比如Tomcat服务器,Java模块化事实标准的OSGi技术;所以,我们有足够的理由认为**选择多ClassLoader架构在大多数情况下是明智之举**。
目前开源的插件方案中,DroidPlugin采用的『激进方案』,Small采用的『保守方案』那么,有没有两种优点兼顾的方案呢??
答案自然是有的。
DroidPlugin和Small的共同点是**两者都是非侵入式的插件框架**;什么是『非侵入式』呢?打个比方,你启动一个插件Activity,直接使用`startActivity`即可,就跟开发普通的apk一样,开发插件和普通的程序对于开发者来说没有什么区别。
如果我们一定程度上放弃这种『侵入性』,那么我们就能实现一个两者优点兼而有之的插件框架!这里我先卖个关子~
OK,本文的内容就到这里了;关于『插件机制对于Activity的处理方式』也就此完结。要说明的是,在本文的『保守方案』其实只处理了代码的加载过程,它并不能加载有资源的apk!所以目前我这个实现基本没什么暖用;当然我这里只是就『代码加载』进行举例;至于资源,那牵扯到另外一个问题——**插件系统的资源管理机制**这个在后续文章的合适机会我会单独讲解。
[1]: 概述.md
[2]: https://github.com/tiann/understand-plugin-framework
[3]: Activity生命周期管理.md
[4]: Hook机制之AMS&PMS.md
[5]: http://androidxref.com/6.0.1_r10/xref/libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
[6]: http://androidxref.com/6.0.1_r10/xref/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
[7]: Hook机制之Binder-Hook.md
================================================
FILE: DOC/tianweishu/ContentProvider插件化.md
================================================
# ContentProvider插件化
目前为止我们已经完成了Android四大组件中Activity,Service以及BroadcastReceiver的插件化,这几个组件各不相同,我们根据它们的特点定制了不同的插件化方案;那么对于ContentProvider,它又有什么特点?应该如何实现它的插件化?
与Activity,BroadcastReceiver等频繁被使用的组件不同,我们接触和使用ContentProvider的机会要少得多;但是,ContentProvider这个组件对于Android系统有着特别重要的作用——作为一种极其方便的**数据共享**的手段,ContentProvider使得广大第三方App能够在壁垒森严的系统中自由呼吸。
在Android系统中,每一个应用程序都有自己的用户ID,而每一个应用程序所创建的文件的读写权限都是只赋予给自己所属的用户,这就限制了应用程序之间相互读写数据的操作。应用程序之间如果希望能够进行交互,只能采取跨进程通信的方式;Binder机制能够满足一般的IPC需求,但是如果应用程序之间需要共享大量数据,单纯使用Binder是很难办到的——我相信大家对于Binder 1M缓冲区以及TransactionTooLargeException一定不陌生;ContentProvider使用了匿名共享内存(Ashmem)机制完成数据共享,因此它可以很方便地完成大量数据的传输。Android系统的短信,联系人,相册,媒体库等等一系列的基础功能都依赖与ContentProvider,它的重要性可见一斑。
既然ContentProvider的核心特性是数据共享,那么要实现它的插件化,必须能让插件能够把它的ContentProvider共享给系统——如果不能「**provide content**」那还叫什么ContentProvider?
但是,如果回想一下Activity等组件的插件化方式,在涉及到「共享」这个问题上,一直没有较好的解决方案:
<!-- more -->
1. 系统中的第三方App无法启动插件中带有特定IntentFilter的Activity,因为系统压根儿感受不到插件中这个真正的Activity的存在。
2. 插件中的静态注册的广播并不真正是静态的,而是使用动态注册广播模拟实现的;这就导致如果宿主程序进程死亡,这个静态广播不会起作用;这个问题的根本原因在由于BroadcastReceiver的IntentFilter的不可预知性,使得我们没有办法把静态广播真正“共享”给系统。
3. 我们没有办法在第三方App中启动或者绑定插件中的Service组件;因为插件的Service并不是真正的Service组件,系统能感知到的只是那个代理Service;因此如果插件如果带有远程Service组件,它根本不能给第三方App提供远程服务。
虽然在插件系统中一派生机勃勃的景象,Activity,Service等插件组件百花齐放,插件与宿主、插件与插件争奇斗艳;但是一旦脱离了插件系统的温室,这一片和谐景象不复存在:插件组件不过是傀儡而已;活着的,只有宿主——整个插件系统就是一座死寂的鬼城,各个插件组件借尸还魂般地依附在宿主身上,了无生机。
既然希望把插件的ContentProvider共享给整个系统,让第三方的App都能获取到我们插件共享的数据,我们必须解决这个问题;下文将会围绕这个目标展开,完成ContentProvider的插件化,并且顺带给出上述问题的解决方案。阅读本文之前,可以先clone一份 [understand-plugin-framework][1],参考此项目的 contentprovider-management 模块。另外,插件框架原理解析系列文章见 [索引][2]。
## ContentProvider工作原理
首先我们还是得分析一下ContentProvider的工作原理,很多插件化的思路,以及一些Hook点的发现都严重依赖于对于系统工作原理的理解;对于ContentProvider的插件化,这一点特别重要。
### 铺垫工作
如同我们通过`startActivity`来启动Activity一样,与ContentProvider打交道的过程也是从Context类的一个方法开始的,这个方法叫做`getContentResolver`,使用ContentProvider的典型代码如下:
```java
ContentResolver resolver = content.getContentResolver();
resolver.query(Uri.parse("content://authority/test"), null, null, null, null);
```
直接去ContextImpl类里面查找的`getContentResolver`实现,发现这个方法返回的类型是android.app.ContextImpl.ApplicationContentResolver,这个类是抽象类android.content.ContentResolver的子类,`resolver.query`实际上是调用父类ContentResolver的`query`实现:
```java
public final @Nullable Cursor query(final @NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
long startTime = SystemClock.uptimeMillis();
ICancellationSignal remoteCancellationSignal = null;
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
remoteCancellationSignal = unstableProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
try {
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
// The remote process has died... but we only hold an unstable
// reference though, so we might recover!!! Let's try!!!!
// This is exciting!!1!!1!!!!1
unstableProviderDied(unstableProvider);
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
qCursor = stableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
}
// 略...
}
```
注意这里面的那个`try..catch`语句,`query`方法首先尝试调用抽象方法acquireUnstableProvider拿到一个IContentProvider对象,并尝试调用这个"unstable"对象的`query`方法,万一调用失败(抛出DeadObjectExceptopn,熟悉Binder的应该了解这个异常)说明ContentProvider所在的进程已经死亡,这时候会尝试调用`acquireProvider`这个抽象方法来获取一个可用的IContentProvider(代码里面那个萌萌的注释说明了一切^_^);由于这两个`acquire*`都是抽象方法,我们可以直接看子类`ApplicationContentResolver`的实现:
```java
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}
```
可以看到这两个抽象方法最终都通过调用`ActivityThread`类的`acquireProvider`获取到IContentProvider,接下来我们看看到底是如何获取到ContentProvider的。
### ContentProvider获取过程
ActivityThread类的`acquireProvider`方法如下,我们需要知道的是,方法的最后一个参数`stable`代表着ContentProvider所在的进程是否存活,如果进程已死,可能需要在必要的时候唤起这个进程;
```java
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
```
这个方法首先通过`acquireExistingProvider`尝试从本进程中获取ContentProvider,如果获取不到,那么再请求`AMS`获取对应ContentProvider;想象一下,如果你查询的是自己App内部的ContentProvider组件,干嘛要劳烦AMS呢?不论是从哪里获取到的ContentProvider,获取完毕之后会调用`installProvider`来安装ContentProvider。
OK打住,我们思考一下,如果要实现ContentProvider的插件化,我们需要完成一些什么工作?开篇的时候我提到了数据共享,那么具体来说,实现插件的数据共享,需要完成什么?ContentProvider是一个数据共享组件,也就是说它不过是**一个携带数据的载体而已**。为了支持跨进程共享,这个载体是**Binder调用**,为了共享大量数据,使用了匿名共享内存;这么说还是有点抽象,那么想一下,给出一个ContentProvider,你能对它做一些什么操作?如果能让插件支持这些操作,不就支持了插件化么?这就是典型的duck type思想——如果一个东西看起来像ContentProvider,用起来也像ContentProvider,那么它就是ContentProvider。
ContentProvider主要支持`query, insert, update, delete`操作,由于这个组件一般工作在别的进程,因此这些调用都是Binder调用。从上面的代码可以看到,这些调用最终都是委托给一个IContentProvider的Binder对象完成的,如果我们Hook掉这个对象,那么对于ContentProvider的所有操作都会被我们拦截掉,这时候我们可以做进一步的操作来完成对于插件ContentProvider组件的支持。要拦截这个过程,我们可以**假装插件的ContentProvider是自己App的ContentProvider**,也就是说,让`acquireExistingProvider`方法可以直接获取到插件的ContentProvider,这样我们就不需要欺骗AMS就能完成插件化了。当然,你也可以选择Hook掉AMS,让AMS的`getContentProvider`方法返回被我们处理过的对象,这也是可行的;但是,为什么要舍近求远呢?
从上文的分析暂时得出结论:我们可以把插件的ContentProvider信息预先放在App进程内部,使得对于ContentProvider执行CURD操作的时候,可以获取到插件的组件,这样或许就可以实现插件化了。具体来说,我们要做的事情就是让`ActivityThread`的`acquireExistingProvider`方法能够返回插件的ContentProvider信息,我们看看这个方法的实现:
```java
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
}
// 略。。
}
}
```
可以看出,App内部自己的ContentProvider信息保存在ActivityThread类的`mProviderMap`中,这个map的类型是ArrayMap<ProviderKey, ProviderClientRecord>;我们当然可以通过反射修改这个成员变量,直接把插件的ContentProvider信息填进去,但是这个ProviderClientRecord对象如何构造?我们姑且看看系统自己是如果填充这个字段的。在ActivityThread类中搜索一遍,发现调用mProviderMap对象的`put`方法的之后`installProviderAuthoritiesLocked`,而这个方法最终被`installProvider`方法调用。在分析ContentProvider的获取过程中我们已经知道,不论是通过本进程的`acquireExistingProvider`还是借助AMS的`getContentProvider`得到ContentProvider,最终都会对这个对象执行`installProvider`操作,也就是「安装」在本进程内部。那么,我们接着看这个`installProvider`做了什么,它是如何「安装」ContentProvider的。
### 进程内部ContentProvider安装过程
首先,如果之前没有“安装”过,那么holder为null,下面的代码会被执行,
```java
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
info.name + " from sourceDir " +
info.applicationInfo.sourceDir);
return null;
}
if (DEBUG_PROVIDER) Slog.v(
TAG, "Instantiating local provider " + info.name);
// XXX Need to create the correct context for this provider.
localProvider.attachInfo(c, info);
```
比较直观,直接load这个ContentProvider所在的类,然后用反射创建出这个ContentProvider对象;但是由于查询是需要进行跨进程通信的,在本进程创建出这个对象意义不大,所以我们需要取出ContentProvider承载跨进程通信的Binder对象IContentProvider;创建出对象之后,接下来就是构建合适的信息,保存在ActivityThread内部,也就是`mProviderMap`:
```java
if (localProvider != null) {
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, "
+ "using existing local provider");
}
provider = pr.mProvider;
} else {
holder = new IActivityManager.ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
} else {
```
以上就是安装代码,不难理解。
### 思路尝试——本地安装
那么,了解了「安装」过程再结合上文的分析,我们似乎可以完成ContentProvider的插件化了——直接把插件的ContentProvider安装在进程内部就行了。如果插件系统有多个进程,那么必须在每个进程都「安装」一遍,如果你熟悉Android进程的启动流程那么就会知道,这个安装ContentProvider的过程适合放在Application类中,因为每个Android进程启动的时候,App的Application类是会被启动的。
看起来实现ContentProvider的思路有了,但是这里实际上有一个严重的缺陷!
我们依然没有解决「共享」的问题。我们只是在插件系统启动的进程里面的ActivityThread的`mProviderMap`给修改了,这使得只有通过插件系统启动的进程,才能感知到插件中的ContentProvider(因为我们手动把插件中的信息install到这个进程中去了);如果第三方的App想要使用插件的ContentProvider,那系统只会告诉它查无此人。
那么,我们应该如何解决共享这个问题呢?看来还是逃不过AMS的魔掌,我们继续跟踪源码,看看如果在本进程查询不到ContentProvider,AMS是如何完成这个过程的。在ActivityThread的`acquireProvider`方法中我们提到,如果`acquireExistingProvider`方法返回null,会调用ActivityManagerNative的`getContentProvider`方法通过AMS查询整个系统中是否存在需要的这个ContentProvider。如果第三方App查询插件系统的ContentProvider必然走的是这个流程,我们仔细分析一下这个过程;
### AMS中的ContentProvider
首先我们查阅ActivityManagerService的`getContentProvider`方法,这个方法间接调用了`getContentProviderImpl`方法;`getContentProviderImpl`方法体相当的长,但是实际上只做了两件事件事(我这就不贴代码了,读者可以对着源码看一遍):
1. 使用PackageManagerService的resolveContentProvider根据Uri中提供的auth信息查阅对应的ContentProivoder的信息ProviderInfo。
2. 根据查询到的ContentProvider信息,尝试将这个ContentProvider组件安装到系统上。
#### 查询ContentProvider组件的过程
查询ContentProvider组件的过程看起来很简单,直接调用PackageManager的`resolveContentProvider`就能从URI中获取到对应的`ProviderInfo`信息:
```java
@Override
public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
// reader
synchronized (mPackages) {
final PackageParser.Provider provider = mProvidersByAuthority.get(name);
PackageSetting ps = provider != null
? mSettings.mPackages.get(provider.owner.packageName)
: null;
return ps != null
&& mSettings.isEnabledLPr(provider.info, flags, userId)
&& (!mSafeMode || (provider.info.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) != 0)
? PackageParser.generateProviderInfo(provider, flags,
ps.readUserState(userId), userId)
: null;
}
}
```
但是实际上我们关心的是,这个`mProvidersByAuthority`里面的信息是如何添加进PackageManagerService的,会在什么时候更新?在PackageManagerService这个类中搜索mProvidersByAuthority.put这个调用,会发现在`scanPackageDirtyLI`会更新`mProvidersByAuthority`这个map的信息,接着往前追踪会发现:**这些信息是在Android系统启动的时候收集的**。也就是说,Android系统在启动的时候会扫描一些App的安装目录,典型的比如/data/app/*,获取这个目录里面的apk文件,读取其AndroidManifest.xml中的信息,然后把这些信息保存在PackageManagerService中。合理猜测,在系统启动之后,安装新的App也会触发对新App中AndroidManifest.xml的操作,感兴趣的读者可以自行翻阅源码。
现在我们知道,查询ContentProvider的信息来源在Android系统启动的时候已经初始化好了,这个过程对于我们第三方app来说是鞭长莫及,想要使用类似在进程内部Hack ContentProvider的查找过程是不可能的。
#### 安装ContentProvider组件的过程
获取到URI对应的ContentProvider的信息之后,接下来就是把它安装到系统上了,这样以后有别的查询操作就可以直接拿来使用;但是这个安装过程AMS是没有办法以一己之力完成的。想象一下App DemoA 查询App DemoB 的某个ContentProviderAppB,那么这个ContentProviderAppB必然存在于DemoB这个App中,AMS所在的进程(system_server)连这个ContentProviderAppB的类都没有,因此,AMS必须委托DemoB完成它的ContentProviderAppB的安装;这里就分两种情况:其一,DemoB这个App已经在运行了,那么AMS直接通知DemoB安装ContentProviderAppB(如果B已经安装了那就更好了);其二,DemoB这个app没在运行,那么必须把B进程唤醒,让它干活;这个过程也就是ActivityManagerService的`getContentProviderImpl`方法所做的,如下代码:
```java
if (proc != null && proc.thread != null) {
if (!proc.pubProviders.containsKey(cpi.name)) {
proc.pubProviders.put(cpi.name, cpr);
try {
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
} else {
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
if (proc == null) {
return null;
}
}
```
如果查询的ContentProvider所在进程处于运行状态,那么AMS会通过这个进程给AMS的ApplicationThread这个Binder对象完成scheduleInstallProvider调用,这个过程比较简单,最终会调用到目标进程的`installProvider`方法,而这个方法我们在上文已经分析过了。我们看一下如果目标进程没有启动,会发生什么情况。
如果ContentProvider所在的进程已经死亡,那么会调用startProcessLocked来启动新的进程,`startProcessLocked`有一系列重载函数,我们一路跟踪,发现最终启动进程的操作交给了`Process`类的`start`方法完成,这个方法通过socket与Zygote进程进行通信,通知Zygote进程fork出一个子进程,然后通过反射调用了之前传递过来的一个入口类的main函数,一般来说这个入口类就是ActivityThread,因此子进程fork出来之后会执行ActivityThread类的main函数。
在我们继续观察子进程ActivityThread的main函数执行之前,我们看看AMS进程这时候会干什么——startProcessLocked之后AMS进程和fork出来的DemoB进程分道扬镳;AMS会继续往下面执行。我们暂时回到AMS的`getContentProviderImpl`方法:
```java
// Wait for the provider to be published...
synchronized (cpr) {
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
return null;
}
try {
if (conn != null) {
conn.waiting = true;
}
cpr.wait();
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
```
你没看错,一个死循环就是糊在上面:AMS进程会通过一个死循环等到进程B完成ContentProvider的安装,等待完成之后会把ContentProvider的信息返回给进程A。那么,我们现在的疑惑是,**进程B在启动之后,在哪个时间点会完成ContentProvider的安装呢?**
我们接着看ActivityThread的main函数,顺便寻找我们上面那个问题的答案;这个分析实际上就是Android App的启动过程,更详细的过程可以参阅老罗的文章 [Android应用程序启动过程源代码分析][4],这里只给出简要调用流程:

最终,DemoB进程启动之后会执行ActivityThread类的handleBindApplication方法,这个方法相当之长,基本完成了App进程启动之后所有必要的操作;这里我们只关心ContentProvider相关的初始化操作,代码如下:
```java
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, providers);
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
// Do this after providers, since instrumentation tests generally start their
// test thread at this point, and we don't want that racing.
try {
mInstrumentation.onCreate(data.instrumentationArgs);
}
catch (Exception e) {
}
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
}
```
仔细观察以上代码,你会发现:**ContentProvider的安装比Application的onCreate回调还要早!!**因此,分析到这里我们已经明白了前面提出的那个问题,**进程启动之后会在Applition类的onCreate 回调之前,在Application对象创建之后完成ContentProvider的安装**。
然后不要忘了,我们的AMS进程还在那傻傻等待DemoB进程完成ContentProviderAppB的安装呢!在DemoB的Application的onCreate回调之前,DemoB的ContentProviderAppB已经安装好了,因此AMS停止等待,把DemoB安装的结果返回给请求这个ContentProvider的DemoA。我们必须对这个时序保持敏感,有时候就是失之毫厘,差之千里!!
到这里,有关ContentProvider的调用过程以及简要的工作原理我们已经分析完毕,关于它如何共享数据,如何使用匿名共享内存这部分不是插件化的重点,感兴趣的可以参考 [Android应用程序组件Content Provider在应用程序之间共享数据的原理分析][5]。
## 不同之处
在实现ContentProvider的插件化之前,通过分析这个组件的工作原理,我们可以得出它的一些与众不同的特性:
1. ContentProvider本身是用来共享数据的,因此它提供一般的CURD服务;它类似HTTP这种无状态的服务,没有Activity,Service所谓的生命周期的概念,服务要么可用,要么不可用;对应着ContentProvider要么启动,要么随着进程死亡;而通常情况下,死亡之后还会被系统启动。所以,ContentProvider,只要有人需要这个服务,系统可以保证是永生的;这是与其他组件的最大不同;完全不用考虑生命周期的概念。
2. ContentProvider被设计为共享数据,这种数据量一般来说是相当大的;熟悉Binder的人应该知道,Binder进行数据传输有1M限制,因此如果要使用Binder传输大数据,必须使用类似socket的方式一段一段的读,也就是说需要自己在上层架设一层协议;ContentProvider并没有采取这种方式,而是采用了Android系统的匿名共享内存机制,利用Binder来传输这个文件描述符,进而实现文件的共享;这是第二个不同,因为其他的三个组建通信都是基于Binder的,只有ContentProvider使用了Ashmem。
3. 一个App启动过程中,ContentProvider组件的启动是非常早的,甚至比Application的onCreate还要早;我们可以利用这个特性结合它不死的特点,完成一些有意义的事情。
4. ContentProvider存在优先查询本进程的特点,使得它的插件化甚至不需要Hook AMS就能完成。
## 思路分析
在分析ContentProvider的工作原理的过程中我们提出了一种插件化方案:在进程启动之初,手动把ContentProvider安装到本进程,使得后续对于插件ContentProvider的请求能够顺利完成。我们也指出它的一个严重缺陷,那就是它只能在插件系统内部掩耳盗铃,在插件系统之外,第三方App依然无法感知到插件中的ContentProvider的存在。
如果插件的ContentProvider组件仅仅是为了共享给其他插件或者宿主程序使用,那么这种方案可以解决问题;不需要Hook AMS,非常简单。
但是,如果希望把插件ContenProvider共享给整个系统呢?在分析AMS中获取ContentProvider的过程中我们了解到,ContentProvider信息的注册是在Android系统启动或者新安装App的时候完成的,而AMS把ContentProvider返回给第三方App也是在system_server进程完成;我们无法对其暗箱操作。
在完成Activity,Service组件的插件化之后,这种限制对我们来说已经是小case了:我们在宿主程序里面注册一个货真价实、被系统认可的StubContentProvider组件,把这个组件共享给第三方App;然后通过**代理分发技术**把第三方App对于插件ContentProvider的请求通过这个StubContentProvider分发给对应的插件。
但是这还存在一个问题,由于第三方App查阅的其实是StubContentProvider,因此他们查阅的URI也必然是StubContentProvider的authority,要查询到插件的ContentProvider,必须把要查询的真正的插件ContentProvider信息传递进来。这个问题的解决方案也很容易,我们可以制定一个「插件查询协议」来实现。
举个例子,假设插件系统的宿主程序在AndroidManifest.xml中注册了一个StubContentProvider,它的Authority为`com.test.host_authority`;由于这个组件被注册在AndroidManifest.xml中,是系统认可的ContentProvider组件,整个系统都是可以使用这个共享组件的,使用它的URI一般为`content://com.test.host_authority`;那么,如果插件系统中存在一个插件,这个插件提供了一个PluginContentProvider,它的Authority为`com.test.plugin_authorith`,因为这个插件的PluginContentProvider没有在宿主程序的AndroidMainifest.xml中注册(预先注册就失去插件的意义了),整个系统是无法感知到它的存在的;前面提到代理分发技术,也就是,我们让第三方App请求宿主程序的StubContentProvider,这个StubContentProvider把请求转发给合适的插件的ContentProvider就能完成了(插件内部通过预先installProvider可以查询所有的ContentProvider组件);这个协议可以有很多,比如说:如果第三方App需要请求插件的StubContentProvider,可以以`content://com.test.host_authority/com.test.plugin_authorith`去查询系统;也就是说,我们假装请求StubContentProvider,把真正的需要请求的PluginContentProvider的Authority放在路径参数里面,StubContentProvider收到这个请求之后,拿到这个真正的Authority去请求插件的PluginContentProvider,拿到结果之后再返回给第三方App。
这样,我们通过「代理分发技术」以及「插件查询协议」可以完美解决「共享」的问题,开篇提到了我们之前对于Activity,Service组件插件化方案中对于「共享」功能的缺失,按照这个思路,基本可以解决这一系列问题。比如,对于第三方App无法绑定插件服务的问题,我们可以注册一个StubService,把真正需要bind的插件服务信息放在intent的某个字段中,然后在StubService的onBind中解析出这个插件服务信息,然后去拿到插件Service组件的Binder对象返回给第三方。
## 实现
上文详细分析了如何实现ContentProvider的插件化,接下来我们就实现这个过程。
### 预先installProvider
要实现预先installProvider,我们首先需要知道,所谓的「预先」到底是在什么时候?
前文我们提到过App进程安装ContentProvider的时机非常之早,在Application类的onCreate回调执行之前已经完成了;这意味着什么?
现在我们对于ContentProvider插件化的实现方式是通过「代理分发技术」,也就是说在请求插件ContentProvider的时候会先请求宿主程序的StubContentProvider;如果一个第三方App查询插件的ContentProvider,而宿主程序没有启动的话,AMS会启动宿主程序并等待宿主程序的StubContentProvider完成安装,**一旦安装完成就会把得到的IContentProvider返回给这个第三方App**;第三方App拿到IContentProvider这个Binder对象之后就可能发起CURD操作,如果这个时候插件ContentProvider还没有启动,那么肯定就会出异常;要记住,“这个时候”可能宿主程序的onCreate还没有执行完毕呢!!
所以,我们基本可以得出结论,预先安装这个所谓的「预先」必须早于Application的onCreate方法,在Android SDK给我们的回调里面,attachBaseContent这个方法是可以满足要求的,它在Application这个对象被创建之后就会立即调用。
解决了时机问题,那么我们接下来就可以安装ContentProvider了。
安装ContentProvider也就是要调用ActivityThread类的`installProvider`方法,这个方法需要的参数有点多,而且它的第二个参数IActivityManager.ContentProviderHolder是一个隐藏类,我们不知道如何构造,就算通过反射构造由于SDK没有暴露稳定性不易保证,我们看看有什么方法调用了这个installProvider。
installContentProviders这个方法直接调用installProvder看起来可以使用,但是它是一个private的方法,还有public的方法吗?继续往上寻找调用链,发现了installSystemProviders这个方法:
```java
public final void installSystemProviders(List<ProviderInfo> providers) {
if (providers != null) {
installContentProviders(mInitialApplication, providers);
}
}
```
但是,我们说过ContentProvider的安装必须相当早,必须在Application类的attachBaseContent方法内,而这个`mInitialApplication`字段是在`onCreate`方法调用之后初始化的,所以,如果直接使用这个`installSystemProviders`势必抛出空指针异常;因此,我们只有退而求其次,选择**通过installContentProviders这个方法完成ContentProvider的安装**
要调用这个方法必须拿到ContentProvider对应的ProviderInfo,这个我们在之前也介绍过,可以通过PackageParser类完成,当然这个类有一些兼容性问题,我们需要手动处理:
```java
/**
* 解析Apk文件中的 <provider>, 并存储起来
* 主要是调用PackageParser类的generateProviderInfo方法
*
* @param apkFile 插件对应的apk文件
* @throws Exception 解析出错或者反射调用出错, 均会抛出异常
*/
public static List<ProviderInfo> parseProviders(File apkFile) throws Exception {
Class<?> packageParserClass = Class.forName("android.content.pm.PackageParser");
Method parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage", File.class, int.class);
Object packageParser = packageParserClass.newInstance();
// 首先调用parsePackage获取到apk对象对应的Package对象
Object packageObj = parsePackageMethod.invoke(packageParser, apkFile, PackageManager.GET_PROVIDERS);
// 读取Package对象里面的services字段
// 接下来要做的就是根据这个List<Provider> 获取到Provider对应的ProviderInfo
Field providersField = packageObj.getClass().getDeclaredField("providers");
List providers = (List) providersField.get(packageObj);
// 调用generateProviderInfo 方法, 把PackageParser.Provider转换成ProviderInfo
Class<?> packageParser$ProviderClass = Class.forName("android.content.pm.PackageParser$Provider");
Class<?> packageUserStateClass = Class.forName("android.content.pm.PackageUserState");
Class<?> userHandler = Class.forName("android.os.UserHandle");
Method getCallingUserIdMethod = userHandler.getDeclaredMethod("getCallingUserId");
int userId = (Integer) getCallingUserIdMethod.invoke(null);
Object defaultUserState = packageUserStateClass.newInstance();
// 需要调用 android.content.pm.PackageParser#generateProviderInfo
Method generateProviderInfo = packageParserClass.getDeclaredMethod("generateProviderInfo",
packageParser$ProviderClass, int.class, packageUserStateClass, int.class);
List<ProviderInfo> ret = new ArrayList<>();
// 解析出intent对应的Provider组件
for (Object service : providers) {
ProviderInfo info = (ProviderInfo) generateProviderInfo.invoke(packageParser, service, 0, defaultUserState, userId);
ret.add(info);
}
return ret;
}
```
解析出ProviderInfo之后,就可以直接调用installContentProvider了:
```java
/**
* 在进程内部安装provider, 也就是调用 ActivityThread.installContentProviders方法
*
* @param context you know
* @param apkFile
* @throws Exception
*/
public static void installProviders(Context context, File apkFile) throws Exception {
List<ProviderInfo> providerInfos = parseProviders(apkFile);
for (ProviderInfo providerInfo : providerInfos) {
providerInfo.applicationInfo.packageName = context.getPackageName();
}
Log.d("test", providerInfos.toString());
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
Method installProvidersMethod = activityThreadClass.getDeclaredMethod("installContentProviders", Context.class, List.class);
installProvidersMethod.setAccessible(true);
installProvidersMethod.invoke(currentActivityThread, context, providerInfos);
}
```
整个安装过程**必须在Application类的attachBaseContent里面完成**:
```java
/**
* 一定需要Application,并且在attachBaseContext里面Hook
* 因为provider的初始化非常早,比Application的onCreate还要早
* 在别的地方hook都晚了。
*
* @author weishu
* @date 16/3/29
*/
public class UPFApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
try {
File apkFile = getFileStreamPath("testcontentprovider-debug.apk");
if (!apkFile.exists()) {
Utils.extractAssets(base, "testcontentprovider-debug.apk");
}
File odexFile = getFileStreamPath("test.odex");
// Hook ClassLoader, 让插件中的类能够被成功加载
BaseDexClassLoaderHookHelper.patchClassLoader(getClassLoader(), apkFile, odexFile);
ProviderHelper.installProviders(base, getFileStreamPath("testcontentprovider-debug.apk"));
} catch (Exception e) {
throw new RuntimeException("hook failed", e);
}
}
}
```
### 代理分发以及协议解析
把插件中的ContentProvider安装到插件系统中之后,在插件内部就可以自由使用这些ContentProvider了;要把这些插件共享给整个系统,我们还需要一个货真价实的ContentProvider组件来执行分发:
```xml
<provider
android:name="com.example.weishu.contentprovider_management.StubContentProvider"
android:authorities="com.example.weishu.contentprovider_management.StubContentProvider"
android:process=":p"
android:exported="true" />
```
第三方App如果要查询到插件的ContentProvider,必须遵循一个「插件查询协议」,这样StubContentProvider才能把对于插件的请求分发到正确的插件组件:
```java
/**
* 为了使得插件的ContentProvder提供给外部使用,我们需要一个StubProvider做中转;
* 如果外部程序需要使用插件系统中插件的ContentProvider,不能直接查询原来的那个uri
* 我们对uri做一些手脚,使得插件系统能识别这个uri;
*
* 这里的处理方式如下:
*
* 原始查询插件的URI应该为:
* content://plugin_auth/path/query
*
* 如果需要查询插件,需要修改为:
*
* content://stub_auth/plugin_auth/path/query
*
* 也就是,我们把插件ContentProvider的信息放在URI的path中保存起来;
* 然后在StubProvider中做分发。
*
* 当然,也可以使用QueryParamerter,比如:
* content://plugin_auth/path/query/ -> content://stub_auth/path/query?plugin=plugin_auth
* @param raw 外部查询我们使用的URI
* @return 插件真正的URI
*/
private Uri getRealUri(Uri raw) {
String rawAuth = raw.getAuthority();
if (!AUTHORITY.equals(rawAuth)) {
Log.w(TAG, "rawAuth:" + rawAuth);
}
String uriString = raw.toString();
uriString = uriString.replaceAll(rawAuth + '/', "");
Uri newUri = Uri.parse(uriString);
Log.i(TAG, "realUri:" + newUri);
return newUri;
}
```
通过以上过程我们就实现了ContentProvider的插件化。需要说明的是,DroidPlugind的插件化与上述介绍的方案有一些不同之处:
1. 首先DroidPlugin并没有选择预先安装的方案,而是选择Hook ActivityManagerNative,拦截它的getContentProvider以及publishContentProvider方法实现对于插件组件的控制;从这里可以看出它对ContentProvider与Service的插件化几乎是相同的,Hook才是DroidPlugin Style ^_^.
2. 然后,关于携带插件信息,或者说「插件查询协议」方面;DroidPlugin把插件信息放在查询参数里面,本文呢则是路径参数;这一点完全看个人喜好。
## 小结
本文我们通过「代理分发技术」以及「插件查询协议」完成了ContentProvider组件的插件化,并且给出了对「插件共享组件」的问题的一般解决方案。值得一提的是,系统的ContentProvider其实是lazy load的,也就是说只有在需要使用的时候才会启动对应的ContentProvider,而我们对于插件的实现则是**预先加载**,这里还有改进的空间,读者可以思考一下解决方案。
由于ContentProvider的使用频度非常低,而很多它使用的场景(比如系统)并不太需要「插件化」,因此在实际的插件方案中,提供ContentProvider插件化的方案非常之少;就算需要实现ContentProvider的插件化,也只是解决插件内部之间共享组件的问题,并没有把插件组件暴露给整个系统。我个人觉得,如果只是希望插件化,那么是否支持ContentProvider无伤大雅,但是,如果希望实现虚拟化或者说容器技术,所有组件是必须支持插件化的。
至此,对于Android系统的四大组件的插件化已经全部介绍完毕;由于是最后一个要介绍的组件,我并没有像之前一样先给出组件的运行原理,然后一通分析最后给出插件方案,而是一边分析代码一边给出自己的思路,把思考——推翻——改进的整个过程完全展现了出来,Android的插件化已经到达了百花齐放的阶段,插件化之路也不只有一条,但是万变不离其宗,希望我的分析和思考对各位读者理解甚至创造插件化方案带来帮助。接下来我会介绍「插件通信机制」,它与本文的ContentProvider以及我反复强调过的一些特性密切相关,敬请期待!
[1]: https://github.com/tiann/understand-plugin-framework
[2]: 概述.md
[3]: http://weishu.me
[4]: http://blog.csdn.net/luoshengyang/article/details/6689748
[5]: http://blog.csdn.net/luoshengyang/article/details/6967204
================================================
FILE: DOC/tianweishu/Hook机制之AMS&PMS.md
================================================
# Hook机制之AMS&PMS
在前面的文章中我们介绍了DroidPlugin的Hook机制,也就是**代理方式**和**Binder Hook**;插件框架通过AOP实现了插件使用和开发的透明性。在讲述DroidPlugin如何实现四大组件的插件化之前,有必要说明一下它对ActivityManagerServiche以及PackageManagerService的Hook方式(以下简称AMS,PMS)。
ActivityManagerService对于FrameWork层的重要性不言而喻,Android的四大组件无一不与它打交道:
1. `startActivity`最终调用了AMS的`startActivity`系列方法,实现了Activity的启动;Activity的生命周期回调,也在AMS中完成;
2. `startService,bindService`最终调用到AMS的startService和bindService方法;
3. 动态广播的注册和接收在`AMS`中完成(静态广播在`PMS`中完成)
4. `getContentResolver`最终从`AMS`的`getContentProvider`获取到ContentProvider
而`PMS`则完成了诸如权限校捡(`checkPermission,checkUidPermission`),Apk meta信息获取(`getApplicationInfo`等),四大组件信息获取(`query`系列方法)等重要功能。
在上文[Android插件化原理解析——Hook机制之Binder Hook][1]中讲述了DroidPlugin的Binder Hook机制;我们知道`AMS`和`PMS`就是以Binder方式提供给应用程序使用的系统服务,理论上我们也可以采用这种方式Hook掉它们。但是由于这两者使用得如此频繁,Framework给他们了一些“特别优待”,这也给了我们相对于Binder Hook更加稳定可靠的hook方式。
<!--more-->
阅读本文之前,可以先clone一份 [understand-plugin-framework][2],参考此项目的`ams-pms-hook`模块。另外,插件框架原理解析系列文章见[索引](http://weishu.me/2016/01/28/understand-plugin-framework-overview/)。
## AMS获取过程
前文提到Android的四大组件无一不与`AMS`相关,也许读者还有些许疑惑;这里我就挑一个例子,依据Android源码来说明,一个简单的`startActivity`是如何调用`AMS`最终通过IPC到system_server的。
不论读者是否知道,我们使用`startActivity`有两种形式:
1. 直接调用`Context`类的`startActivity`方法;这种方式启动的Activity没有Activity栈,因此不能以standard方式启动,必须加上`FLAG_ACTIVITY_NEW_TASK`这个Flag。
2. 调用被`Activity`类重载过的`startActivity`方法,通常在我们的Activity中直接调用这个方法就是这种形式;
### Context.startActivity
我们查看`Context`类的`startActivity`方法,发现这竟然是一个抽象类;查看`Context`的类继承关系图如下:
<img src="http://7xp3xc.com1.z0.glb.clouddn.com/201601/1457322345547.png" width="329"/>
我们看到诸如`Activity`,`Service`等并没有直接继承`Context`,而是继承了`ContextWrapper`;继续查看`ContextWrapper`的实现:
```java
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
```
WTF!! 果然人如其名,只是一个wrapper而已;这个`mBase`是什么呢?这里我先直接告诉你,它的真正实现是`ContextImpl`类;至于为什么,有一条思路:*mBase是在ContextWrapper构造的时候传递进来的,那么在ContextWrapper构造的时候可以找到答案*
什么时候会构造ContextWrapper呢?它的子类`Application`,`Service`等被创建的时候。
可以在App的主线程`AcitivityThread`的`performLaunchActivit`方法里面找到答案;更详细的解析可以参考老罗的[ Android应用程序启动过程源代码分析][3]
好了,我们姑且当作已经知道Context.startActivity最终使用了ContextImpl里面的方法,代码如下:
```java
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity)null, intent, -1, options);
}
```
代码相当简单;我们知道了两件事:
1. 其一,我们知道了在Service等非Activity的Context里面启动Activity为什么需要添加`FLAG_ACTIVITY_NEW_TASK`;
2. 其二,真正的`startActivity`使用了`Instrumentation`类的`execStartActivity`方法;继续跟踪:
```java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
// ... 省略无关代码
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess();
// ----------------look here!!!!!!!!!!!!!!!!!!!
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}
```
到这里我们发现真正调用的是`ActivityManagerNative`的`startActivity`方法;如果你不清楚`ActivityManager`,`ActivityManagerService`以及`ActivityManagerNative`之间的关系;建议先仔细阅读我之前关于Binder的文章 [Binder学习指南][4]。
### Activity.startActivity
Activity类的`startActivity`方法相比Context而言直观了很多;这个`startActivity`通过若干次调用辗转到达`startActivityForResult`这个方法,在这个方法内部有如下代码:
```java
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
```
可以看到,其实通过Activity和ContextImpl类启动Activity并无本质不同,他们都通过`Instrumentation`这个辅助类调用到了`ActivityManagerNative`的方法。
## Hook AMS
OK,我们到现在知道;其实`startActivity`最终通过`ActivityManagerNative`这个方法远程调用了`AMS`的`startActivity`方法。那么这个`ActivityManagerNative`是什么呢?
ActivityManagerNative实际上就是`ActivityManagerService`这个远程对象的Binder代理对象;每次需要与AMS打交道的时候,需要借助这个代理对象通过驱动进而完成IPC调用。
我们继续看`ActivityManagerNative`的`getDefault()`方法做了什么:
```java
static public IActivityManager getDefault() {
return gDefault.get();
}
```
`gDefault`这个静态变量的定义如下:
```java
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity
IActivityManager am = asInterface(
return am;
}
};
```
由于整个Framework与AMS打交道是如此频繁,framework使用了一个单例把这个`AMS`的代理对象保存了起来;这样只要需要与`AMS`进行IPC调用,获取这个单例即可。这是`AMS`这个系统服务与其他普通服务的不同之处,也是我们不通过Binder Hook的原因——我们只需要简单地Hook掉这个单例即可。
这里还有一点小麻烦:Android不同版本之间对于如何保存这个单例的代理对象是不同的;Android 2.x系统直接使用了一个简单的静态变量存储,Android 4.x以上抽象出了一个Singleton类;具体的差异可以使用`grepcode`进行比较:[差异][5]
我们以4.x以上的代码为例说明如何Hook掉`AMS`;方法使用的动态代理,如果有不理解的,可以参考之前的系列文章[Android插件化原理解析——Hook机制之动态代理][6]
```java
Class<?> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
// 获取 gDefault 这个字段, 想办法替换它
Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");
gDefaultField.setAccessible(true);
Object gDefault = gDefaultField.get(null);
// 4.x以上的gDefault是一个 android.util.Singleton对象; 我们取出这个单例里面的字段
Class<?> singleton = Class.forName("android.util.Singleton");
Field mInstanceField = singleton.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
// ActivityManagerNative 的gDefault对象里面原始的 IActivityManager对象
Object rawIActivityManager = mInstanceField.get(gDefault);
// 创建一个这个对象的代理对象, 然后替换这个字段, 让我们的代理对象帮忙干活
Class<?> iActivityManagerInterface = Class.forName("android.app.IActivityManager");
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[] { iActivityManagerInterface }, new IActivityManagerHandler(rawIActivityManager));
mInstanceField.set(gDefault, proxy);
```
好了,我们hook成功之后启动Activity看看会发生什么:
```
D/HookHelper﹕ hey, baby; you are hook!!
D/HookHelper﹕ method:activityResumed called with args:[android.os.BinderProxy@9bc71b2]
D/HookHelper﹕ hey, baby; you are hook!!
D/HookHelper﹕ method:activityIdle called with args:[android.os.BinderProxy@9bc71b2, null, false]
D/HookHelper﹕ hey, baby; you are hook!!
D/HookHelper﹕ method:startActivity called with args:[android.app.ActivityThread$ApplicationThread@17e750c, com.weishu.upf.ams_pms_hook.app, Intent { act=android.intent.action.VIEW dat=http://wwww.baidu.com/... }, null, android.os.BinderProxy@9bc71b2, null, -1, 0, null, null]
D/HookHelper﹕ hey, baby; you are hook!!
D/HookHelper﹕ method:activityPaused called with args:[android.os.BinderProxy@9bc71b2]
```
可以看到,简单的几行代码,`AMS`已经被我们完全劫持了!! 至于劫持了能干什么,自己发挥想象吧~
DroidPlugin关于`AMS`的Hook,可以查看`IActivityManagerHook`这个类,它处理了我上述所说的兼容性问题,其他原理相同。另外,也许有童鞋有疑问了,你用`startActivity`为例怎么能确保Hook掉这个静态变量之后就能保证所有使用`AMS`的入口都被Hook了呢?
答曰:无他,唯手熟尔。
Android Framewrok层对于四大组件的处理,调用`AMS`服务的时候,全部都是通过使用这种方式;若有疑问可以自行查看源码。你可以从`Context`类的startActivity, startService,bindService, registerBroadcastReceiver, getContentResolver 等等入口进行跟踪,最终都会发现它们都会使用ActivityManagerNative的这个`AMS`代理对象来完成对远程AMS的访问。
## PMS获取过程
`PMS`的获取也是通过Context完成的,具体就是`getPackageManager`这个方法;我们姑且当作已经知道了Context的实现在ContextImpl类里面,直奔`ContextImpl`类的`getPackageManager`方法:
```java
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
```
可以看到,这里干了两件事:
1. 真正的`PMS`的代理对象在`ActivityThread`类里面
2. `ContextImpl`通过`ApplicationPackageManager`对它还进行了一层包装
我们继续查看`ActivityThread`类的`getPackageManager`方法,源码如下:
```java
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
sPackageManager = IPackageManager.Stub.asInterface(b);
return sPackageManager;
}
```
可以看到,和`AMS`一样,`PMS`的Binder代理对象也是一个全局变量存放在一个静态字段中;我们可以如法炮制,Hook掉PMS。
现在我们的目的很明切,如果需要Hook `PMS`有两个地方需要Hook掉:
1. `ActivityThread`的静态字段`sPackageManager`
2. 通过Context类的`getPackageManager`方法获取到的`ApplicationPackageManager`对象里面的`mPM`字段。
## Hook PMS
现在使用代理Hook应该是轻车熟路了吧,通过上面的分析,我们Hook两个地方;代码信手拈来:
```java
// 获取全局的ActivityThread对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
// 获取ActivityThread里面原始的 sPackageManager
Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
sPackageManagerField.setAccessible(true);
Object sPackageManager = sPackageManagerField.get(currentActivityThread);
// 准备好代理对象, 用来替换原始的对象
Class<?> iPackageManagerInterface = Class.forName("android.content.pm.IPackageManager");
Object proxy = Proxy.newProxyInstance(iPackageManagerInterface.getClassLoader(),
new Class<?>[] { iPackageManagerInterface },
new HookHandler(sPackageManager));
// 1. 替换掉ActivityThread里面的 sPackageManager 字段
sPackageManagerField.set(currentActivityThread, proxy);
// 2. 替换 ApplicationPackageManager里面的 mPM对象
PackageManager pm = context.getPackageManager();
Field mPmField = pm.getClass().getDeclaredField("mPM");
mPmField.setAccessible(true);
mPmField.set(pm, proxy);
```
好了,Hook完毕我们验证以下结论;调用一下`PMS`的`getInstalledApplications`方法,打印日志如下:
```
03-07 15:07:27.187 8306-8306/com.weishu.upf.ams_pms_hook.app D/IActivityManagerHandler﹕ hey, baby; you are hook!!
03-07 15:07:27.187 8306-8306/com.weishu.upf.ams_pms_hook.app D/IActivityManagerHandler﹕ method:getInstalledApplications called with args:[0, 0]
```
OK,我们又成功劫持了`PackageManager`!!DroidPlugin 处理PMS的代码可以在`IPackageManagerHook`查看。
在结束讲解PackageManager的Hook之前,我们需要说明一点;那就是`Context`的实现类里面没有使用静态全局变量来保存`PMS`的代理对象,而是每拥有一个`Context`的实例就持有了一个`PMS`代理对象的引用;所以这里有个很蛋疼的事情,那就是我们如果想要完全Hook住`PMS`,需要精确控制整个进程内部创建的`Context`对象;所幸,插件框架中,插件的Activity,Service,ContentProvider,Broadcast等所有使用到Context的地方,都是由框架控制创建的;因此我们要小心翼翼地替换掉所有这些对象持有的`PMS`代理对象。
我前面也提到过,**静态变量和单例**都是良好的Hook点,这里很好地反证了这句话:想要Hook掉一个实例变量该是多么麻烦!
## 小结
写到这里,关于DroidPlugin的Hook技术的讲解已经完结了;我相信读者或多或少地认识到,其实Hook并不是一项神秘的技术;一个干净,透明的框架少不了AOP,而AOP也少不了Hook。
我所讲解的Hook仅仅使用反射和动态代理技术,更加强大的Hook机制可以进行**字节码编织**,比如J2EE广泛使用了cglib和asm进行AOP编程;而Android上现有的插件框架还是加载编译时代码,采用动态生成类的技术理论上也是可行的;之前有一篇文章[Android动态加载黑科技 动态创建Activity模式][7],就讲述了这种方式;现在全球的互联网公司不排除有用这种技术实现插件框架的可能 ;我相信不远的未来,这种技术也会在Android上大放异彩。
了解完Hook技术之后,接下来的系列文章会讲述DroidPlugin对Android四大组件在插件系统上的处理,插件框架对于这一部分的实现是DroidPlugin的精髓,Hook只不过是工具而已。学习这部分内容需要对于Activity,Service,Broadcast以及ContentProvider的工作机制有一定的了解,因此我也会在必要的时候穿插讲解一些Android Framework的知识;我相信这一定会对读者大有裨益。
[1]: Hook机制之Binder-Hook.md
[2]: https://github.com/tiann/understand-plugin-framework
[3]: http://blog.csdn.net/luoshengyang/article/details/6689748
[4]: http://weishu.me/2016/01/12/binder-index-for-newer/
[5]: http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/app/ActivityManagerNative.java/?v=diff&id2=2.3.3_r1
[6]: Hook机制之代理Hook.md
[7]: https://segmentfault.com/a/1190000004077469
================================================
FILE: DOC/tianweishu/Hook机制之Binder-Hook.md
================================================
# Hook机制之Binder-Hook
Android系统通过Binder机制给应用程序提供了一系列的系统服务,诸如`ActivityManagerService`,`ClipboardManager`, `AudioManager`等;这些广泛存在系统服务给应用程序提供了诸如任务管理,音频,视频等异常强大的功能。
插件框架作为各个插件的管理者,为了使得插件能够**无缝地**使用这些系统服务,自然会对这些系统服务做出一定的改造(Hook),使得插件的开发和使用更加方便,从而大大降低插件的开发和维护成本。比如,Hook住`ActivityManagerService`可以让插件无缝地使用`startActivity`方法而不是使用特定的方式(比如that语法)来启动插件或者主程序的任意界面。
我们把这种Hook系统服务的机制称之为Binder Hook,因为本质上这些服务提供者都是存在于系统各个进程的Binder对象。因此,要理解接下来的内容必须了解Android的Binder机制,可以参考我之前的文章[Binder学习指南][1]
<!--more-->
阅读本文之前,可以先clone一份 [understand-plugin-framework][3],参考此项目的`binder-hook` 模块。另外,插件框架原理解析系列文章见[索引][2]。
## 系统服务的获取过程
我们知道系统的各个远程service对象都是以Binder的形式存在的,而这些Binder有一个管理者,那就是`ServiceManager`;我们要Hook掉这些service,自然要从这个`ServiceManager`下手,不然星罗棋布的Binder广泛存在于系统的各个角落,要一个个找出来还真是大海捞针。
回想一下我们使用系统服务的时候是怎么干的,想必这个大家一定再熟悉不过了:通过`Context`对象的`getSystemService`方法;比如要使用`ActivityManager`:
```java
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
```
可是这个貌似跟`ServiceManager`没有什么关系啊?我们再查看`getSystemService`方法;(Context的实现在`ContextImpl`里面):
```java
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
```
很简单,所有的service对象都保存在一张`map`里面,我们再看这个map是怎么初始化的:
```
registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
IAccountManager service = IAccountManager.Stub.asInterface(b);
return new AccountManager(ctx, service);
}});
```
在`ContextImpl`的静态初始化块里面,有的Service是像上面这样初始化的;可以看到,确实使用了`ServiceManager`;当然还有一些service并没有直接使用`ServiceManager`,而是做了一层包装并返回了这个包装对象,比如我们的`ActivityManager`,它返回的是`ActivityManager`这个包装对象:
```
registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
}});
```
但是在`ActivityManager`这个类内部,也使用了`ServiceManager`;具体来说,因为ActivityManager里面所有的核心操作都是使用`ActivityManagerNative.getDefault()`完成的。那么这个语句干了什么呢?
```java
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
IActivityManager am = asInterface(b);
return am;
}
};
```
因此,通过分析我们得知,系统Service的使用其实就分为两步:
```java
IBinder b = ServiceManager.getService("service_name"); // 获取原始的IBinder对象
IXXInterface in = IXXInterface.Stub.asInterface(b); // 转换为Service接口
```
## 寻找Hook点
在[插件框架原理解析——Hook机制之动态代理][4]里面我们说过,Hook分为三步,最关键的一步就是寻找Hook点。我们现在已经搞清楚了系统服务的使用过程,那么就需要找出在这个过程中,在哪个环节是最合适hook的。
由于系统服务的使用者都是对第二步获取到的`IXXInterface`进行操作,因此如果我们要hook掉某个系统服务,**只需要把第二步的`asInterface`方法返回的对象修改为为我们Hook过的对象就可以了。**
### asInterface过程
接下来我们分析`asInterface`方法,然后想办法把这个方法的返回值修改为我们Hook过的系统服务对象。这里我们以系统剪切版服务为例,源码位置为`android.content.IClipboard`,`IClipboard.Stub.asInterface`方法代码如下:
```java
public static android.content.IClipboard asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); // Hook点
if (((iin != null) && (iin instanceof android.content.IClipboard))) {
return ((android.content.IClipboard) iin);
}
return new android.content.IClipboard.Stub.Proxy(obj);
}
```
这个方法的意思就是:先查看本进程是否存在这个Binder对象,如果有那么直接就是本进程调用了;如果不存在那么创建一个代理对象,让代理对象委托驱动完成跨进程调用。
观察这个方法,前面的那个if语句判空返回肯定动不了手脚;最后一句调用构造函数然后直接返回我们也是无从下手,要修改`asInterface`方法的返回值,我们唯一能做的就是从这一句下手:
```
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); // Hook点
```
我们可以尝试修改这个`obj`对象的`queryLocalInterface`方法的返回值,并保证这个返回值符合接下来的`if`条件检测,那么就达到了修改`asInterface`方法返回值的目的。
而这个`obj`对象刚好是我们第一步返回的`IBinder`对象,接下来我们尝试对这个`IBinder`对象的`queryLocalInterface`方法进行hook。
### getService过程
上文分析得知,我们想要修改`IBinder`对象的`queryLocalInterface`方法;获取`IBinder`对象的过程如下:
```
IBinder b = ServiceManager.getService("service_name");
```
因此,我们希望能修改这个`getService`方法的返回值,让这个方法返回一个我们伪造过的`IBinder`对象;这样,我们可以在自己伪造的`IBinder`对象的`queryLocalInterface`方法作处理,进而使得`asInterface`方法返回在`queryLocalInterface`方法里面处理过的值,最终实现hook系统服务的目的。
在跟踪这个`getService`方法之前我们思考一下,由于系统服务是一系列的远程Service,它们的本体,也就是Binder本地对象一般都存在于某个单独的进程,在这个进程之外的其他进程存在的都是这些Binder本地对象的代理。因此在我们的进程里面,存在的也只是这个Binder代理对象,我们也只能对这些Binder代理对象下手。(如果这一段看不懂,建议不要往下看了,先看[Binder学习指南][1])
然后,这个`getService`是一个静态方法,如果此方法什么都不做,拿到Binder代理对象之后直接返回;那么我们就无能为力了:我们没有办法拦截一个静态方法,也没有办法获取到这个静态方法里面的局部变量(即我们希望修改的那个Binder代理对象)。
接下来就可以看这个`getService`的代码了:
```java
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
```
天无绝人之路!`ServiceManager`为了避免每次都进行跨进程通信,把这些Binder代理对象缓存在一张`map`里面。
我们可以替换这个map里面的内容为Hook过的`IBinder`对象,由于系统在`getService`的时候每次都会优先查找缓存,因此返回给使用者的都是被我们修改过的对象,从而达到瞒天过海的目的。
总结一下,要达到修改系统服务的目的,我们需要如下两步:
1. 首先肯定需要**伪造一个系统服务对象**,接下来就要想办法让`asInterface`能够返回我们的这个伪造对象而不是原始的系统服务对象。
2. 通过上文分析我们知道,只要让`getService`返回`IBinder`对象的`queryLocalInterface`方法直接返回我们伪造过的系统服务对象就能达到目的。所以,我们需要**伪造一个IBinder对象**,主要是修改它的`queryLocalInterface`方法,让它返回我们伪造的系统服务对象;然后把这个伪造对象放置在`ServiceManager`的缓存`map`里面即可。
我们通过Binder机制的*优先查找本地Binder对象*的这个特性达到了Hook掉系统服务对象的目的。因此`queryLocalInterface`也失去了它原本的意义(只查找本地Binder对象,没有本地对象返回null),这个方法只是一个傀儡,是我们实现hook系统对象的桥梁:我们通过这个“漏洞”让`asInterface`永远都返回我们伪造过的对象。由于我们接管了`asInterface`这个方法的全部,我们伪造过的这个系统服务对象不能是只拥有本地Binder对象(原始`queryLocalInterface`方法返回的对象)的能力,还要有Binder代理对象操纵驱动的能力。
接下来我们就以Hook系统的剪切版服务为例,用实际代码来说明,如何Hook掉系统服务。
## Hook系统剪切版服务
### 伪造剪切版服务对象
首先我们用代理的方式伪造一个剪切版服务对象,关于如何使用代理的方式进行hook以及其中的原理,可以查看[插件框架原理解析——Hook机制之动态代理][4]。
具体代码如下,我们用动态代理的方式Hook掉了`hasPrimaryClip()`,`getPrimaryClip()`这两个方法:
```java
public class BinderHookHandler implements InvocationHandler {
private static final String TAG = "BinderHookHandler";
// 原始的Service对象 (IInterface)
Object base;
public BinderHookHandler(IBinder base, Class<?> stubClass) {
try {
Method asInterfaceMethod = stubClass.getDeclaredMethod("asInterface", IBinder.class);
// IClipboard.Stub.asInterface(base);
this.base = asInterfaceMethod.invoke(null, base);
} catch (Exception e) {
throw new RuntimeException("hooked failed!");
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 把剪切版的内容替换为 "you are hooked"
if ("getPrimaryClip".equals(method.getName())) {
Log.d(TAG, "hook getPrimaryClip");
return ClipData.newPlainText(null, "you are hooked");
}
// 欺骗系统,使之认为剪切版上一直有内容
if ("hasPrimaryClip".equals(method.getName())) {
return true;
}
return method.invoke(base, args);
}
}
```
注意,我们拿到原始的`IBinder`对象之后,如果我们希望使用被Hook之前的系统服务,并不能直接使用这个`IBinder`对象,而是需要使用`asInterface`方法将它转换为`IClipboard`接口;因为`getService`方法返回的`IBinder`实际上是一个**裸Binder代理对象**,它只有与驱动打交道的能力,但是它并不能独立工作,需要人指挥它;`asInterface`方法返回的`IClipboard.Stub.Proxy`类的对象通过操纵这个裸`BinderProxy`对象从而实现了具体的`IClipboard`接口定义的操作。
### 伪造`IBinder` 对象
在上一步中,我们已经伪造好了系统服务对象,现在要做的就是想办法让`asInterface`方法返回我们伪造的对象了;我们伪造一个`IBinder`对象:
```java
public class BinderProxyHookHandler implements InvocationHandler {
private static final String TAG = "BinderProxyHookHandler";
// 绝大部分情况下,这是一个BinderProxy对象
// 只有当Service和我们在同一个进程的时候才是Binder本地对象
// 这个基本不可能
IBinder base;
Class<?> stub;
Class<?> iinterface;
public BinderProxyHookHandler(IBinder base) {
this.base = base;
try {
this.stub = Class.forName("android.content.IClipboard$Stub");
this.iinterface = Class.forName("android.content.IClipboard");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("queryLocalInterface".equals(method.getName())) {
Log.d(TAG, "hook queryLocalInterface");
// 这里直接返回真正被Hook掉的Service接口
// 这里的 queryLocalInterface 就不是原本的意思了
// 我们肯定不会真的返回一个本地接口, 因为我们接管了 asInterface方法的作用
// 因此必须是一个完整的 asInterface 过的 IInterface对象, 既要处理本地对象,也要处理代理对象
// 这只是一个Hook点而已, 它原始的含义已经被我们重定义了; 因为我们会永远确保这个方法不返回null
// 让 IClipboard.Stub.asInterface 永远走到if语句的else分支里面
return Proxy.newProxyInstance(proxy.getClass().getClassLoader(),
// asInterface 的时候会检测是否是特定类型的接口然后进行强制转换
// 因此这里的动态代理生成的类型信息的类型必须是正确的
new Class[] { IBinder.class, IInterface.class, this.iinterface },
new BinderHookHandler(base, stub));
}
Log.d(TAG, "method:" + method.getName());
return method.invoke(base, args);
}
}
```
我们使用动态代理的方式伪造了一个跟原始`IBinder`一模一样的对象,然后在这个伪造的`IBinder`对象的`queryLocalInterface`方法里面返回了我们第一步创建的**伪造过的系统服务对象**;注意看注释,详细解释可以看[代码][3]
### 替换ServiceManager的`IBinder`对象
现在就是万事具备,只欠东风了;我们使用反射的方式修改`ServiceManager`类里面缓存的Binder对象,使得`getService`方法返回我们伪造的`IBinder`对象,进而`asInterface`方法使用伪造`IBinder`对象的`queryLocalInterface`方法返回了我们伪造的系统服务对象。代码较简单,如下:
```java
final String CLIPBOARD_SERVICE = "clipboard";
// 下面这一段的意思实际就是: ServiceManager.getService("clipboard");
// 只不过 ServiceManager这个类是@hide的
Class<?> serviceManager = Class.forName("android.os.ServiceManager");
Method getService = serviceManager.getDeclaredMethod("getService", String.class);
// ServiceManager里面管理的原始的Clipboard Binder对象
// 一般来说这是一个Binder代理对象
IBinder rawBinder = (IBinder) getService.invoke(null, CLIPBOARD_SERVICE);
// Hook 掉这个Binder代理对象的 queryLocalInterface 方法
// 然后在 queryLocalInterface 返回一个IInterface对象, hook掉我们感兴趣的方法即可.
IBinder hookedBinder = (IBinder) Proxy.newProxyInstance(serviceManager.getClassLoader(),
new Class<?>[] { IBinder.class },
new BinderProxyHookHandler(rawBinder));
// 把这个hook过的Binder代理对象放进ServiceManager的cache里面
// 以后查询的时候 会优先查询缓存里面的Binder, 这样就会使用被我们修改过的Binder了
Field cacheField = serviceManager.getDeclaredField("sCache");
cacheField.setAccessible(true);
Map<String, IBinder> cache = (Map) cacheField.get(null);
cache.put(CLIPBOARD_SERVICE, hookedBinder);
```
接下来,在app里面使用剪切版,比如长按进行粘贴之后,剪切版的内容永远都是`you are hooked`了;这样,我们Hook系统服务的目的宣告完成!详细的代码参见 [github][3]。
也许你会问,插件框架会这么hook吗?如果不是那么插件框架hook这些干什么?插件框架当然不会做替换文本这么无聊的事情,DroidPlugin插件框架管理插件使得插件就像是主程序一样,因此插件需要使用主程序的剪切版,插件之间也会共用剪切版;其他的一些系统服务也类似,这样就可以达到插件和宿主程序之间的天衣服缝,水乳交融!另外,`ActivityManager`以及`PackageManager`这两个系统服务虽然也可以通过这种方式hook,但是由于它们的重要性和特殊性,DroidPlugin使用了另外一种方式,我们会单独讲解。
[1]: http://weishu.me/2016/01/12/binder-index-for-newer/
[2]: 概述.md
[3]: https://github.com/tiann/understand-plugin-framework
[4]: Hook机制之代理Hook.md
[5]: http://weishu.me/
================================================
FILE: DOC/tianweishu/Hook机制之代理Hook.md
================================================
# Hook机制之动态代理
使用代理机制进行API Hook进而达到方法增强是框架的常用手段,比如J2EE框架Spring通过动态代理优雅地实现了AOP编程,极大地提升了Web开发效率;同样,插件框架也广泛使用了代理机制来增强系统API从而达到插件化的目的。本文将带你了解基于动态代理的Hook机制。
阅读本文之前,可以先clone一份 [understand-plugin-framework][1],参考此项目的`dynamic-proxy-hook`模块。另外,插件框架原理解析系列文章见[索引](http://weishu.me/2016/01/28/understand-plugin-framework-overview/)。
## 代理是什么
为什么需要代理呢?其实这个代理与日常生活中的“代理”,“中介”差不多;比如你想海淘买东西,总不可能亲自飞到国外去购物吧,这时候我们使用第三方海淘服务比如惠惠购物助手等;同样拿购物为例,有时候第三方购物会有折扣比如当初的米折网,这时候我们可以少花点钱;当然有时候这个“代理”比较坑,坑我们的钱,坑我们的货。
从这个例子可以看出来,代理可以实现**方法增强**,比如常用的*日志*,*缓存*等;也可以实现方法拦截,通过代理方法修改原方法的参数和返回值,从而实现某种不可告人的目的~接下来我们用代码解释一下。
<!--more-->
## 静态代理
静态代理,是最原始的代理方式;假设我们有一个购物的接口,如下:
```java
public interface Shopping {
Object[] doShopping(long money);
}
```
它有一个原始的实现,我们可以理解为亲自,直接去商店购物:
```java
public class ShoppingImpl implements Shopping {
@Override
public Object[] doShopping(long money) {
System.out.println("逛淘宝 ,逛商场,买买买!!");
System.out.println(String.format("花了%s块钱", money));
return new Object[] { "鞋子", "衣服", "零食" };
}
}
```
好了,现在我们自己没时间但是需要买东西,于是我们就找了个代理帮我们买:
```java
public class ProxyShopping implements Shopping {
Shopping base;
ProxyShopping(Shopping base) {
this.base = base;
}
@Override
public Object[] doShopping(long money) {
// 先黑点钱(修改输入参数)
long readCost = (long) (money * 0.5);
System.out.println(String.format("花了%s块钱", readCost));
// 帮忙买东西
Object[] things = base.doShopping(readCost);
// 偷梁换柱(修改返回值)
if (things != null && things.length > 1) {
things[0] = "被掉包的东西!!";
}
return things;
}
```
很不幸,我们找的这个代理有点坑,坑了我们的钱还坑了我们的货;先忍忍。
## 动态代理
传统的静态代理模式需要为每一个需要代理的类写一个代理类,如果需要代理的类有几百个那不是要累死?为了更优雅地实现代理模式,JDK提供了动态代理方式,可以简单理解为JVM可以在运行时帮我们动态生成一系列的代理类,这样我们就不需要手写每一个静态的代理类了。依然以购物为例,用动态代理实现如下:
```java
public static void main(String[] args) {
Shopping women = new ShoppingImpl();
// 正常购物
System.out.println(Arrays.toString(women.doShopping(100)));
// 招代理
women = (Shopping) Proxy.newProxyInstance(Shopping.class.getClassLoader(),
women.getClass().getInterfaces(), new ShoppingHandler(women));
System.out.println(Arrays.toString(women.doShopping(100)));
}
```
动态代理主要处理`InvocationHandler`和`Proxy`类;完整代码可以见[github][1]
## 代理Hook
我们知道代理有比原始对象更强大的能力,比如飞到国外买东西,比如坑钱坑货;那么很自然,如果我们自己创建代理对象,然后把原始对象替换为我们的代理对象,那么就可以在这个代理对象为所欲为了;修改参数,替换返回值,我们称之为Hook。
下面我们Hook掉`startActivity`这个方法,使得每次调用这个方法之前输出一条日志;(当然,这个输入日志有点点弱,只是为了展示原理;只要你想,你想可以替换参数,拦截这个`startActivity`过程,使得调用它导致启动某个别的Activity,指鹿为马!)
首先我们得找到被Hook的对象,我称之为Hook点;什么样的对象比较好Hook呢?自然是**容易找到的对象**。什么样的对象容易找到?**静态变量和单例**;在一个进程之内,静态变量和单例变量是相对不容易发生变化的,因此非常容易定位,而普通的对象则要么无法标志,要么容易改变。我们根据这个原则找到所谓的Hook点。
然后我们分析一下`startActivity`的调用链,找出合适的Hook点。我们知道对于`Context.startActivity`(Activity.startActivity的调用链与之不同),由于`Context`的实现实际上是`ContextImpl`;我们看`ConetxtImpl`类的`startActivity`方法:
```java
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity)null, intent, -1, options);
}
```
这里,实际上使用了`ActivityThread`类的`mInstrumentation`成员的`execStartActivity`方法;注意到,`ActivityThread` 实际上是主线程,而主线程一个进程只有一个,因此这里是一个良好的Hook点。
接下来就是想要Hook掉我们的主线程对象,也就是把这个主线程对象里面的`mInstrumentation`给替换成我们修改过的代理对象;要替换主线程对象里面的字段,首先我们得拿到主线程对象的引用,如何获取呢?`ActivityThread`类里面有一个静态方法`currentActivityThread`可以帮助我们拿到这个对象类;但是`ActivityThread`是一个隐藏类,我们需要用反射去获取,代码如下:
```java
// 先获取到当前的ActivityThread对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
```
拿到这个`currentActivityThread`之后,我们需要修改它的`mInstrumentation`这个字段为我们的代理对象,我们先实现这个代理对象,由于JDK动态代理只支持接口,而这个`Instrumentation`是一个类,没办法,我们只有手动写静态代理类,覆盖掉原始的方法即可。(`cglib`可以做到基于类的动态代理,这里先不介绍)
```java
public class EvilInstrumentation extends Instrumentation {
private static final String TAG = "EvilInstrumentation";
// ActivityThread中原始的对象, 保存起来
Instrumentation mBase;
public EvilInstrumentation(Instrumentation base) {
mBase = base;
}
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
// Hook之前, XXX到此一游!
Log.d(TAG, "\n执行了startActivity, 参数如下: \n" + "who = [" + who + "], " +
"\ncontextThread = [" + contextThread + "], \ntoken = [" + token + "], " +
"\ntarget = [" + target + "], \nintent = [" + intent +
"], \nrequestCode = [" + requestCode + "], \noptions = [" + options + "]");
// 开始调用原始的方法, 调不调用随你,但是不调用的话, 所有的startActivity都失效了.
// 由于这个方法是隐藏的,因此需要使用反射调用;首先找到这个方法
try {
Method execStartActivity = Instrumentation.class.getDeclaredMethod(
"execStartActivity",
Context.class, IBinder.class, IBinder.class, Activity.class,
Intent.class, int.class, Bundle.class);
execStartActivity.setAccessible(true);
return (ActivityResult) execStartActivity.invoke(mBase, who,
contextThread, token, target, intent, requestCode, options);
} catch (Exception e) {
// 某该死的rom修改了 需要手动适配
throw new RuntimeException("do not support!!! pls adapt it");
}
}
}
```
Ok,有了代理对象,我们要做的就是偷梁换柱!代码比较简单,采用反射直接修改:
```java
public static void attachContext() throws Exception{
// 先获取到当前的ActivityThread对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
currentActivityThreadMethod.setAccessible(true);
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
// 拿到原始的 mInstrumentation字段
Field mInstrumentationField = activityThreadClass.getDeclaredField("mInstrumentation");
mInstrumentationField.setAccessible(true);
Instrumentation mInstrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread);
// 创建代理对象
Instrumentation evilInstrumentation = new EvilInstrumentation(mInstrumentation);
// 偷梁换柱
mInstrumentationField.set(currentActivityThread, evilInstrumentation);
}
```
好了,我们启动一个Activity测试一下,结果如下:
<img src="http://7xp3xc.com1.z0.glb.clouddn.com/201512/1453981415720.png" width="866"/>
可见,Hook确实成功了!这就是使用代理进行Hook的原理——偷梁换柱。整个Hook过程简要总结如下:
1. 寻找Hook点,原则是静态变量或者单例对象,尽量Hook pulic的对象和方法,非public不保证每个版本都一样,需要适配。
2. 选择合适的代理方式,如果是接口可以用动态代理;如果是类可以手动写代理也可以使用cglib。
3. 偷梁换柱——用代理对象替换原始对象
完整代码参照:[understand-plugin-framework][1];里面留有一个作业:我们目前仅Hook了`Context`类的`startActivity`方法,但是`Activity`类却使用了自己的`mInstrumentation`;你可以尝试Hook掉Activity类的`startActivity`方法。
[1]: https://github.com/tiann/understand-plugin-framework
================================================
FILE: DOC/tianweishu/Service插件化.md
================================================
# Service插件化
在 [Activity生命周期管理][1] 以及 [广播的管理][2] 中我们详细探讨了Android系统中的Activity、BroadcastReceiver组件的工作原理以及它们的插件化方案,相信读者已经对Android Framework和插件化技术有了一定的了解;本文将探讨Android四大组件之一——Service组件的插件化方式。
与Activity, BroadcastReceiver相比,Service组件的不同点在哪里呢?我们能否用与之相同的方式实现Service的插件化?如果不行,它们的差别在哪里,应该如何实现Service的插件化?
我们接下来将围绕这几个问题展开,最终给出Service组件的插件化方式;阅读本文之前,可以先clone一份 [understand-plugin-framework][3],参考此项目的 service-management 模块。另外,插件框架原理解析系列文章见[索引][4]。
<!--more-->
## Service工作原理
连Service的工作原理都不了解,谈何插件化?知己知彼。
Service分为两种形式:以startService**启动**的服务和用bindService**绑定**的服务;由于这两个过程大体相似,这里以稍复杂的`bindService`为例分析Service组件的工作原理。
绑定Service的过程是通过`Context`类的`bindService`完成的,这个方法需要三个参数:第一个参数代表想要绑定的Service的Intent,第二个参数是一个ServiceConnetion,我们可以通过这个对象接收到Service绑定成功或者失败的回调;第三个参数则是绑定时候的一些FLAG;关于服务的基本概念,可以参阅 [官方文档][5]。(现在汉化了哦,E文不好童鞋的福音)
Context的具体实现在ContextImpl类,ContextImpl中的`bindService`方法直接调用了`bindServiceCommon`方法,此方法源码如下:
```java
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
// important
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess();
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
}
```
大致观察就能发现这个方法最终通过ActivityManagerNative借助AMS进而完成Service的绑定过程,在跟踪AMS的`bindService`源码之前,我们关注一下这个方法开始处创建的`sd`变量。这个变量的类型是`IServiceConnection`,如果读者还有印象,我们在 [广播的管理][2] 一文中也遇到过类似的处理方式——IIntentReceiver;所以,这个IServiceConnection与IApplicationThread以及IIntentReceiver相同,都是ActivityThread给AMS提供的用来与之进行通信的Binder对象;这个接口的实现类为LoadedApk.ServiceDispatcher。
这个方法最终调用了ActivityManagerNative的bindService,而这个方法的真正实现在AMS里面,源码如下:
```java
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
// 略去参数校检
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
```
bindService这个方法相当简单,只是做了一些参数校检之后直接调用了ActivityServices类的`bindServiceLocked`方法:
```java
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags,
String callingPackage, int userId) throws TransactionTooLargeException {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
// 参数校检,略
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
// 结果校检, 略
ServiceRecord s = res.record;
final long origId = Binder.clearCallingIdentity();
try {
// ... 不关心, 略
mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
s.appInfo.uid, s.name, s.processName);
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
// 对connection进行处理, 方便存取,略
clist.add(c);
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
return 0;
}
}
// 与BIND_AUTO_CREATE不同的启动FLAG,原理与后续相同,略
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
```
这个方法比较长,我这里省去了很多无关代码,只列出关键逻辑;首先它通过`retrieveServiceLocked`方法获取到了intent匹配到的需要bind到的Service组件`res`;然后把ActivityThread传递过来的IServiceConnection使用ConnectionRecord进行了包装,方便接下来使用;最后如果启动的FLAG为BIND_AUTO_CREATE,那么调用`bringUpServiceLocked`开始创建Service,我们跟踪这个方法:(非这种FLAG的代码已经省略,可以自行跟踪)
```java
private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting) throws TransactionTooLargeException {
// 略。。
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
// 1. important !!!
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
} else {
app = r.isolatedProc;
}
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
if (app == null) {
// 2. important !!!
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
// 略。。
return null;
}
```
这个方案同样也很长,但是实际上非常简单:注意我注释的两个important的地方,如果Service所在的进程已经启动,那么直接调用`realStartServiceLocked`方法来**真正**启动Service组件;如果Service所在的进程还没有启动,那么先在AMS中记下这个要启动的Service组件,然后通过`startProcessLocked`启动新的进程。
我们先看Service进程已经启动的情况,也即`realStartServiceLocked`分支:
```java
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
// 略。。
boolean created = false;
try {
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
mAm.appDiedLocked(app);
throw e;
} finally {
// 略。。
}
requestServiceBindingsLocked(r, execInFg);
// 不关心,略。。
}
```
这个方法首先调用了app.thread的scheduleCreateService方法,我们知道,这是一个IApplicationThread对象,它是App所在进程提供给AMS的用来与App进程进行通信的Binder对象,这个Binder的Server端在ActivityThread的ApplicationThread类,因此,我们跟踪ActivityThread类,这个方法的实现如下:
```java
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
```
它不过是转发了一个消息给ActivityThread的`H`这个Handler,`H`类收到这个消息之后,直接调用了ActivityThread类的`handleCreateService`方法,如下:
```java
private void handleCreateService(CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
}
try {
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}
} catch (Exception e) {
}
}
```
看到这段代码,是不是似曾相识?!没错,这里与Activity组件的创建过程如出一辙!所以这里就不赘述了,可以参阅 [Activity生命周期管理][1]。
需要注意的是,这里Service类的创建过程与Activity是略微有点不同的,虽然都是通过ClassLoader通过反射创建,但是Activity却把创建过程委托给了Instrumentation类,而Service则是直接进行。
OK,现在ActivityThread里面的`handleCreateService`方法成功创建出了Service对象,并且调用了它的`onCreate`方法;到这里我们的Service已经启动成功。`scheduleCreateService`这个Binder调用过程结束,代码又回到了AMS进程的`realStartServiceLocked`方法。这里我们不得不感叹Binder机制的精妙,如此简洁方便高效的跨进程调用,在进程之间来回穿梭,游刃有余。
`realStartServiceLocked`方法的代码如下:
```java
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
// 略。。
boolean created = false;
try {
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
mAm.appDiedLocked(app);
throw e;
} finally {
// 略。。
}
requestServiceBindingsLocked(r, execInFg);
// 不关心,略。。
}
```
这个方法在完成`scheduleCreateService`这个binder调用之后,执行了一个`requestServiceBindingsLocked`方法;看方法名好像于「绑定服务」有关,它简单地执行了一个遍历然后调用了另外一个方法:
```java
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.thread == null) {
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
// 不关心,略。。
}
return true;
}
```
可以看到,这里又通过IApplicationThread这个Binder进行了一次IPC调用,我们跟踪ActivityThread类里面的ApplicationThread的`scheduleBindService`方法,发现这个方法不过通过Handler转发了一次消息,真正的处理代码在`handleBindService`里面:
```java
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
}
} catch (Exception e) {
}
}
}
```
我们要Bind的Service终于在这里完成了绑定!绑定之后又通过ActivityManagerNative这个Binder进行一次IPC调用,我们查看AMS的`publishService`方法,这个方法简单第调用了`publishServiceLocked`方法,源码如下:
```java
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
continue;
}
try {
c.conn.connected(r.name, service);
} catch (Exception e) {
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
```
还记得我们之前提到的那个IServiceConnection吗?在`bindServiceLocked`方法里面,我们把这个IServiceConnection放到了一个ConnectionRecord的List中存放在ServiceRecord里面,这里所做的就是取出已经被Bind的这个Service对应的IServiceConnection对象,然后调用它的`connected`方法;我们说过,这个IServiceConnection也是一个Binder对象,它的Server端在LoadedApk.ServiceDispatcher里面。代码到这里已经很明确了,由于分析过程过长,再继续估计大家要瞌睡了;接下来的过程非常简单,感兴趣的读者自行查阅LoadedApk.ServiceDispatcher的`connected`方法,一路跟踪弄清楚ServiceConnection回调过程,完成最后的拼图!
最后提一点,以上我们分析了Service所在进程已经存在的情况,如果Service所在进程不存在,那么会调用startProcessLocked方法创建一个新的进程,并把需要启动的Service放在一个队列里面;创建进程的过程通过Zygote fork出来,进程创建成功之后会调用ActivityThread的main方法,在这个main方法里面间接调用到了AMS的attachApplication方法,在AMS的attachApplication里面会检查刚刚那个待启动Service队列里面的内容,并执行Service的启动操作;之后的启动过程与进程已经存在的情况下相同;可以自行分析。
## Service的插件化思路
现在我们已经明白了Service组件的工作原理,可对如何实现Service的插件化依然是一头雾水。
从上文的源码分析来看,Service组件与Activity有着非常多的相似之处:它们都是通过Context类完成启动,接着通过ActivityMnagaerNative进入AMS,最后又通过IApplicationThread这个Binder IPC到App进程的Binder线程池,然后通过H转发消息到App进程的主线程,最终完成组件生命周期的回调;对于Service组件,看起来好像可以沿用Activity组件的插件化方式:Hook掉ActivityManagerNative以及`H`类,但事实真的如此吗?
### Service与Activity的异同
Service组件和Activity组件有什么不同?这些不同使得我们对于插件化方案的选择又有什么影响?
#### 用户交互对于生命周期的影响
首先,Activity与Service组件最大的不同点在于,Activity组件可以与用户进行交互;这一点意味着用户的行为会对Activity组件产生影响,对我们来说最重要的影响就是Activity组件的生命周期;用户点击按钮从界面A跳转到界面B,会引起A和B这两个Activity一系列生命周期的变化。而Service组件则代表后台任务,除了内存不足系统回收之外,它的生命周期完全由我们的代码控制,与用户的交互无关。
这意味着什么?
Activity组件的生命周期受用户交互影响,而这种变化只有Android系统才能感知,因此我们必须把插件的Activity交给系统管理,才能拥有完整的生命周期;但Service组件的生命周期不受外界因素影响,那么自然而然,我们可以**手动控制它的生命周期**,就像我们对于BroadcastReceiver的插件化方式一样!Activity组件的插件化无疑是比较复杂的,为了把插件Activity交给系统管理进而拥有完整生命周期,我们设计了一个天衣无缝的方案骗过了AMS;既然Service的生命周期可以由我们自己控制,那么我们可以有更简单的方案实现它的插件化。
#### Activity的任务栈
上文指出了Activity和Service组件在处理用户交互方面的不同,这使得我们对于Service组建的插件化可以选择一种较为简单的方式;也许你会问,那采用Activity插件化的那一套技术能够实现Service组件的插件化吗?
很遗憾,答案是不行的。虽然Activity的插件化技术更复杂,但是这种方案并不能完成Service组件的插件化——复杂的方案并不意味了它能处理更多的问题。
原因在于Activity拥有任务栈的概念。或许你觉得任务栈并不是什么了不起的东西,但是,这确实是Service组件与Activity组件插件化方式分道扬镳的根本原因。
任务栈的概念使得Activtiy的创建就代表着入栈,销毁则代表出栈;又由于Activity代表着与用户交互的界面,所以这个栈的深度不可能太深——Activity栈太深意味着用户需要狂点back键才能回到初始界面,这种体验显然有问题;因此,插件框架要处理的Activity数量其实是有限的,所以我们在AndroidManifest.xml中声明有限个StubActivity就能满足插件启动近乎无限个插件Activity的需求。
但是Service组件不一样,理论情况下,可以启动的Service组件是无限的——除了硬件以及内存资源,没有什么限制它的数目;如果采用Activity的插件化方式,就算我们在AndroidMafenist.xml中声明再多的StubService,总有不能满足插件中要启动的Service数目的情况出现。也许有童鞋会说,可以用一个StubService对应多个插件Service,这确实能解决部分问题;但是,下面的这个区别让这种设想彻底泡汤。
#### Service无法拥有多实例
Service组件与Activity组件另外一个不同点在于,对同一个Service调用多次startService并不会启动多个Service实例,而非特定Flag的Activity是可以允许这种情况存在的,因此如果用StubService的方式,为了实现Service的这种特性,必须建立一个StubService到插件Service的一个Map,Map的这种一一对应关系使得我们使用一个StubService对应多个插件Service的计划成为天方夜谭。
至此,结论已经非常清晰——对于Service组件的插件化,我们不能简单地套用Activity的方案。
### 如何实现Service的插件化?
上文指出,我们不能套用Activity的方案实现Service组件的插件化,可以通过手动控制Service组件的生命周期实现;我们先来看一下Service的生命周期:

从图中可以看出,Service的生命周期相当简单:整个生命周期从调用 onCreate() 开始起,到 onDestroy() 返回时结束。对于非绑定服务,就是从startService调用到stopService或者stopSelf调用。对于绑定服务,就是bindService调用到unbindService调用;
如果要手动控制Service组件的生命周期,我们只需要模拟出这个过程即可;而实现这一点并不复杂:
1. 如果以startService方式启动插件Service,直接回调要启动的Service对象的onStartCommand方法即可;如果用stopService或者stopSelf的方式停止Service,只需要回调对应的Service组件的onDestroy方法。
2. 如果用bindService方式绑定插件Service,可以调用对应Service对应的onBind方法,获取onBind方法返回的Binder对象,然后通过ServiceConnection对象进行回调统计;unBindService的实现同理。
#### 完全手动控制
现在我们已经有了实现思路,那么具体如何实现呢?
我们必须在startService,stopService等方法被调用的时候拿到控制权,才能手动去控制Service的生命周期;要达到这一目的非常简单——Hook ActivityManagerNative即可。在Activity的插件化方案中我们就通过这种方式接管了startActivity调用,相信读者并不陌生。
我们Hook掉ActivityManagerNative之后,可以拦截对于startService以及stopService等方法的调用;拦截之后,我们可以直接对插件Service进行操作:
1. 拦截到startService之后,如果Service还没有创建就直接创建Service对象(可能需要加载插件),然后调用这个Service的onCreate,onStartCommond方法;如果Service已经创建,获取到原来创建的Service对象并执行其onStartCommand方法。
2. 拦截到stopService之后,获取到对应的Service对象,直接调用这个Service的onDestroy方法。
这种方案简直简单得让人不敢相信!很可惜,这么干是不行的。
首先,Service存在的意义在于它作为一个后台任务,拥有相对较高运行时优先级;除非在内存及其不足威胁到前台Activity的时候,这个组件才会被系统杀死。上述这种实现完全把Service当作一个普通的Java对象使用了,因此并没有完全实现Service所具备的能力。
其次,Activity以及Service等组件是可以指定进程的,而让Service运行在某个特定进程的情况非常常见——所谓的远程Service;用上述这种办法压根儿没有办法让某个Service对象运行在一个别的进程。Android系统给开发者控制进程的机会太少了,要么在AndroidManifest.xml中通过process属性指定,要么借助Java的Runtime类或者native的fork;这几种方式都无法让我们以一种简单的方式配合上述方案达到目的。
#### 代理分发技术
既然我们希望插件的Service具有一定的运行时优先级,那么一个货真价实的Service组件是必不可少的——只有这种被系统认可的真正的Service组件才具有所谓的运行时优先级。
因此,我们可以注册一个真正的Service组件ProxyService,让这个Service承载一个真正的Service组件所具备的能力(进程优先级等);当启动插件的服务比如PluginService的时候,我们统一启动这个ProxyService,当这个ProxyService运行起来之后,再在它的onStartCommand等方法里面进行分发,执行PluginService的onStartCommond等对应的方法;我们把这种方案形象地称为「代理分发技术」
代理分发技术也可以完美解决插件Service可以运行在不同的进程的问题——我们可以在AndroidManifest.xml中注册多个ProxyService,指定它们的process属性,让它们运行在不同的进程;当启动的插件Service希望运行在一个新的进程时,我们可以选择某一个合适的ProxyService进行分发。也许有童鞋会说,那得注册多少个ProxyService才能满足需求啊?理论上确实存在这问题,但事实上,一个App使用超过10个进程的几乎没有;因此这种方案是可行的。
## Service插件化的实现
现在我们已经设计出了Service组件的插件化方案,接下来我们以startService以及stopService为例实现这个过程。
### 注册代理Service
我们需要一个货真价实的Service组件来承载进程优先级等功能,因此需要在AndroidManifest.xml中声明一个或者多个(用以支持多进程)这样的Sevice:
```xml
<service
android:name="com.weishu.upf.service_management.app.ProxyService"
android:process="plugin01"/>
```
### 拦截startService等调用过程
要手动控制Service组件的生命周期,需要拦截startService,stopService等调用,并且把启动插件Service全部重定向为启动ProxyService(保留原始插件Service信息);这个拦截过程需要Hook ActvityManagerNative,我们对这种技术应该是轻车熟路了;不了解的童鞋可以参考之前的文章 [Hook机制之AMS&PMS][6] 。
```java
public static void hookActivityManagerNative() throws ClassNotFoundException,
NoSuchMethodException, InvocationTargetException,
IllegalAccessException, NoSuchFieldException {
Class<?> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");
gDefaultField.setAccessible(true);
Object gDefault = gDefaultField.get(null);
// gDefault是一个 android.util.Singleton对象; 我们取出这个单例里面的字段
Class<?> singleton = Class.forName("android.util.Singleton");
Field mInstanceField = singleton.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
// ActivityManagerNative 的gDefault对象里面原始的 IActivityManager对象
Object rawIActivityManager = mInstanceField.get(gDefault);
// 创建一个这个对象的代理对象, 然后替换这个字段, 让我们的代理对象帮忙干活
Class<?> iActivityManagerInterface = Class.forName("android.app.IActivityManager");
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[] { iActivityManagerInterface }, new IActivityManagerHandler(rawIActivityManager));
mInstanceField.set(gDefault, proxy);
}
```
我们在收到startService,stopService之后可以进行具体的操作,对于startService来说,就是直接替换启动的插件Service为ProxyService等待后续处理,代码如下:
```java
if ("startService".equals(method.getName())) {
// API 23:
// public ComponentName startService(IApplicationThread caller, Intent service,
// String resolvedType, int userId) throws RemoteException
// 找到参数里面的第一个Intent 对象
Pair<Integer, Intent> integerIntentPair = foundFirstIntentOfArgs(args);
Intent newIntent = new Intent();
// 代理Service的包名, 也就是我们自己的包名
String stubPackage = UPFApplication.getContext().getPackageName();
// 这里我们把启动的Service替换为ProxyService, 让ProxyService接收生命周期回调
ComponentName componentName = new ComponentName(stubPackage, ProxyService.class.getName());
newIntent.setComponent(componentName);
// 把我们原始要启动的TargetService先存起来
newIntent.putExtra(AMSHookHelper.EXTRA_TARGET_INTENT, integerIntentPair.second);
// 替换掉Intent, 达到欺骗AMS的目的
args[integerIntentPair.first] = newIntent;
Log.v(TAG, "hook method startService success");
return method.invoke(mBase, args);
}
```
对stopService的处理略有不同但是大同小异,读者可以上 [github][3] 查阅源码。
### 分发Service
Hook ActivityManagerNative之后,所有的插件Service的启动都被重定向了到了我们注册的ProxyService,这样可以保证我们的插件Service有一个真正的Service组件作为宿主;但是要执行特定插件Service的任务,我们必须把这个任务分发到真正要启动的Service上去;以`onStart`为例,在启动ProxyService之后,会收到ProxyService的`onStart`回调,我们可以在这个方法里面把具体的任务交给原始要启动的插件Service组件:
```java
public void onStart(Intent intent, int startId) {
Log.d(TAG, "onStart() called with " + "intent = [" + intent + "], startId = [" + startId + "]");
// 分发Service
ServiceManager.getInstance().onStart(intent, startId);
super.onStart(intent, startId);
}
```
#### 加载Service
我们可以在ProxyService里面把任务转发给真正要启动的插件Service组件,要完成这个过程肯定需要创建一个对应的插件Service对象,比如PluginService;但是通常情况下插件存在与单独的文件之中,正常的方式是无法创建这个PluginService对象的,宿主程序默认的ClassLoader无法加载插件中对应的这个类;所以,要创建这个对应的PluginService对象,必须先完成插件的加载过程,让这个插件中的所有类都可以被正常访问;这种技术我们在之前专门讨论过,并给出了「激进方案」和「保守方案」,不了解的童鞋可以参考文章 [插件加载机制][7];这里我选择代码较少的「保守方案」为例(Droid Plugin中采用的激进方案):
```java
public static void patchClassLoader(ClassLoader cl, File apkFile, File optDexFile)
throws IllegalAccessException, NoSuchMethodException, IOException, InvocationTargetException, InstantiationException, NoSuchFieldException {
// 获取 BaseDexClassLoader : pathList
Field pathListField = DexClassLoader.class.getSuperclass().getDeclaredField("pathList");
pathListField.setAccessible(true);
Object pathListObj = pathListField.get(cl);
// 获取 PathList: Element[] dexElements
Field dexElementArray = pathListObj.getClass().getDeclaredField("dexElements");
dexElementArray.setAccessible(true);
Object[] dexElements = (Object[]) dexElementArray.get(pathListObj);
// Element 类型
Class<?> elementClass = dexElements.getClass().getComponentType();
// 创建一个数组, 用来替换原始的数组
Object[] newElements = (Object[]) Array.newInstance(elementClass, dexElements.length + 1);
// 构造插件Element(File file, boolean isDirectory, File zip, DexFile dexFile) 这个构造函数
Constructor<?> constructor = elementClass.getConstructor(File.class, boolean.class, File.class, DexFile.class);
Object o = constructor.newInstance(apkFile, false, apkFile, DexFile.loadDex(apkFile.getCanonicalPath(), optDexFile.getAbsolutePath(), 0));
Object[] toAddElementArray = new Object[] { o };
// 把原始的elements复制进去
System.arraycopy(dexElements, 0, newElements, 0, dexElements.length);
// 插件的那个element复制进去
System.arraycopy(toAddElementArray, 0, newElements, dexElements.length, toAddElementArray.length);
// 替换
dexElementArray.set(pathListObj, newElements);
}
```
#### 匹配过程
上文中我们把启动插件Service重定向为启动ProxyService,现在ProxyService已经启动,因此必须把控制权交回原始的PluginService;在加载插件的时候,我们存储了插件中所有的Service组件的信息,因此,只需要根据Intent里面的Component信息就可以取出对应的PluginService。
```java
private ServiceInfo selectPluginService(Intent pluginIntent) {
for (ComponentName componentName : mServiceInfoMap.keySet()) {
if (componentName.equals(pluginIntent.getComponent())) {
return mServiceInfoMap.get(componentName);
}
}
return null;
}
```
#### 创建以及分发
插件被加载之后,我们就需要创建插件Service对应的Java对象了;由于这些类是在运行时动态加载进来的,肯定不能直接使用`new`关键字——我们需要使用反射机制。但是下面的代码创建出插件Service对象能满足要求吗?
```java
ClassLoader cl = getClassLoader();
Service service = cl.loadClass("com.plugin.xxx.PluginService1");
```
Service作为Android系统的组件,最重要的特点是它具有`Context`;所以,直接通过反射创建出来的这个PluginService就是一个壳子——没有Context的Service能干什么?因此我们需要给将要创建的Service类创建出Conetxt;但是Context应该如何创建呢?我们平时压根儿没有这么干过,Context都是系统给我们创建好的。既然这样,我们可以参照一下系统是如何创建Service对象的;在上文的Service源码分析中,在ActivityThread类的handleCreateService完成了这个步骤,摘要如下:
```java
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
}
try {
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
```
可以看到,系统也是通过反射创建出了对应的
gitextract_kra60iuy/ ├── .gitignore ├── DOC/ │ ├── .gitignore │ ├── hejunlin/ │ │ ├── LICENSE │ │ ├── 插件占坑,四大组件动态注册前奏(一) 系统Activity的启动流程.md │ │ ├── 插件占坑,四大组件动态注册前奏(三) 系统BroadCast的注册发送流程.md │ │ ├── 插件占坑,四大组件动态注册前奏(二) 系统Service的启动流程.md │ │ ├── 插件开发之360 DroidPlugin源码分析(一)初识.md │ │ ├── 插件开发之360 DroidPlugin源码分析(三)Binder代理.md │ │ ├── 插件开发之360 DroidPlugin源码分析(二)Hook机制.md │ │ ├── 插件开发之360 DroidPlugin源码分析(五)Service预注册占坑.md │ │ └── 插件开发之360 DroidPlugin源码分析(四)Activity预注册占坑.md │ ├── tianweishu/ │ │ ├── .gitignore │ │ ├── Activity生命周期管理.md │ │ ├── BroadcastReceiver插件化.md │ │ ├── ClassLoader管理.md │ │ ├── ContentProvider插件化.md │ │ ├── Hook机制之AMS&PMS.md │ │ ├── Hook机制之Binder-Hook.md │ │ ├── Hook机制之代理Hook.md │ │ ├── Service插件化.md │ │ └── 概述.md │ └── 插件机制介绍.pptx ├── LICENSE ├── project/ │ ├── .gitignore │ ├── Libraries/ │ │ └── DroidPlugin/ │ │ ├── LICENSE.txt │ │ ├── build.gradle │ │ ├── lib/ │ │ │ └── layoutlib.jar │ │ ├── proguard-project.txt │ │ ├── project.properties │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── aidl/ │ │ │ ├── android/ │ │ │ │ └── app/ │ │ │ │ └── IServiceConnection.aidl │ │ │ └── com/ │ │ │ └── morgoo/ │ │ │ └── droidplugin/ │ │ │ └── pm/ │ │ │ ├── IApplicationCallback.aidl │ │ │ ├── IPackageDataObserver.aidl │ │ │ └── IPluginManager.aidl │ │ ├── java/ │ │ │ └── com/ │ │ │ └── morgoo/ │ │ │ ├── droidplugin/ │ │ │ │ ├── MyCrashHandler.java │ │ │ │ ├── PluginApplication.java │ │ │ │ ├── PluginHelper.java │ │ │ │ ├── PluginManagerService.java │ │ │ │ ├── PluginPatchManager.java │ │ │ │ ├── PluginServiceProvider.java │ │ │ │ ├── am/ │ │ │ │ │ ├── BaseActivityManagerService.java │ │ │ │ │ ├── MyActivityManagerService.java │ │ │ │ │ ├── RunningActivities.java │ │ │ │ │ ├── RunningProcessList.java │ │ │ │ │ ├── ServiceStubMap.java │ │ │ │ │ └── StaticProcessList.java │ │ │ │ ├── core/ │ │ │ │ │ ├── Env.java │ │ │ │ │ ├── PluginClassLoader.java │ │ │ │ │ ├── PluginDirHelper.java │ │ │ │ │ └── PluginProcessManager.java │ │ │ │ ├── hook/ │ │ │ │ │ ├── BaseHookHandle.java │ │ │ │ │ ├── Hook.java │ │ │ │ │ ├── HookFactory.java │ │ │ │ │ ├── HookedMethodHandler.java │ │ │ │ │ ├── binder/ │ │ │ │ │ │ ├── BinderHook.java │ │ │ │ │ │ ├── IAppOpsServiceBinderHook.java │ │ │ │ │ │ ├── IAudioServiceBinderHook.java │ │ │ │ │ │ ├── IClipboardBinderHook.java │ │ │ │ │ │ ├── IContentServiceBinderHook.java │ │ │ │ │ │ ├── IDisplayManagerBinderHook.java │ │ │ │ │ │ ├── IGraphicsStatsBinderHook.java │ │ │ │ │ │ ├── IInputMethodManagerBinderHook.java │ │ │ │ │ │ ├── ILocationManagerBinderHook.java │ │ │ │ │ │ ├── IMediaRouterServiceBinderHook.java │ │ │ │ │ │ ├── IMmsBinderHook.java │ │ │ │ │ │ ├── IMountServiceBinderHook.java │ │ │ │ │ │ ├── INotificationManagerBinderHook.java │ │ │ │ │ │ ├── IPhoneSubInfoBinderHook.java │ │ │ │ │ │ ├── ISearchManagerBinderHook.java │ │ │ │ │ │ ├── ISessionManagerBinderHook.java │ │ │ │ │ │ ├── ISmsBinderHook.java │ │ │ │ │ │ ├── ISubBinderHook.java │ │ │ │ │ │ ├── ITelephonyBinderHook.java │ │ │ │ │ │ ├── ITelephonyRegistryBinderHook.java │ │ │ │ │ │ ├── IWifiManagerBinderHook.java │ │ │ │ │ │ ├── IWindowManagerBinderHook.java │ │ │ │ │ │ ├── MyServiceManager.java │ │ │ │ │ │ ├── ServiceManagerBinderHook.java │ │ │ │ │ │ └── ServiceManagerCacheBinderHook.java │ │ │ │ │ ├── handle/ │ │ │ │ │ │ ├── IActivityManagerHookHandle.java │ │ │ │ │ │ ├── IAppOpsServiceHookHandle.java │ │ │ │ │ │ ├── IAudioServiceHookHandle.java │ │ │ │ │ │ ├── IClipboardHookHandle.java │ │ │ │ │ │ ├── IContentProviderInvokeHandle.java │ │ │ │ │ │ ├── IContentServiceHandle.java │ │ │ │ │ │ ├── IDisplayManagerHookHandle.java │ │ │ │ │ │ ├── IGraphicsStatsHookHandle.java │ │ │ │ │ │ ├── IInputMethodManagerHookHandle.java │ │ │ │ │ │ ├── ILocationManagerHookHandle.java │ │ │ │ │ │ ├── IMediaRouterServiceHookHandle.java │ │ │ │ │ │ ├── IMmsHookHandle.java │ │ │ │ │ │ ├── IMountServiceHookHandle.java │ │ │ │ │ │ ├── INotificationManagerHookHandle.java │ │ │ │ │ │ ├── IPackageManagerHookHandle.java │ │ │ │ │ │ ├── IPhoneSubInfoHookHandle.java │ │ │ │ │ │ ├── ISearchManagerHookHandle.java │ │ │ │ │ │ ├── ISessionManagerHookHandle.java │ │ │ │ │ │ ├── ISmsHookHandle.java │ │ │ │ │ │ ├── ISubBinderHookHandle.java │ │ │ │ │ │ ├── ITelephonyHookHandle.java │ │ │ │ │ │ ├── ITelephonyRegistryHookHandle.java │ │ │ │ │ │ ├── IWifiManagerHookHandle.java │ │ │ │ │ │ ├── IWindowManagerHookHandle.java │ │ │ │ │ │ ├── IWindowSessionInvokeHandle.java │ │ │ │ │ │ ├── LibCoreHookHandle.java │ │ │ │ │ │ ├── PluginCallback.java │ │ │ │ │ │ ├── PluginInstrumentation.java │ │ │ │ │ │ ├── ReplaceCallingPackageHookedMethodHandler.java │ │ │ │ │ │ └── WebViewFactoryProviderHookHandle.java │ │ │ │ │ ├── proxy/ │ │ │ │ │ │ ├── IActivityManagerHook.java │ │ │ │ │ │ ├── IContentProviderHook.java │ │ │ │ │ │ ├── IPackageManagerHook.java │ │ │ │ │ │ ├── IWindowSessionHook.java │ │ │ │ │ │ ├── InstrumentationHook.java │ │ │ │ │ │ ├── LibCoreHook.java │ │ │ │ │ │ ├── PluginCallbackHook.java │ │ │ │ │ │ ├── ProxyHook.java │ │ │ │ │ │ └── WebViewFactoryProviderHook.java │ │ │ │ │ └── xhook/ │ │ │ │ │ └── SQLiteDatabaseHook.java │ │ │ │ ├── pm/ │ │ │ │ │ ├── IPluginManagerImpl.java │ │ │ │ │ ├── PluginManager.java │ │ │ │ │ └── parser/ │ │ │ │ │ ├── IntentMatcher.java │ │ │ │ │ ├── PackageParser.java │ │ │ │ │ ├── PackageParserApi15.java │ │ │ │ │ ├── PackageParserApi16.java │ │ │ │ │ ├── PackageParserApi20.java │ │ │ │ │ ├── PackageParserApi21.java │ │ │ │ │ ├── PackageParserApi22.java │ │ │ │ │ ├── PackageParserApi22Preview1.java │ │ │ │ │ └── PluginPackageParser.java │ │ │ │ ├── reflect/ │ │ │ │ │ ├── FieldUtils.java │ │ │ │ │ ├── MemberUtils.java │ │ │ │ │ ├── MethodUtils.java │ │ │ │ │ ├── Utils.java │ │ │ │ │ └── Validate.java │ │ │ │ └── stub/ │ │ │ │ ├── AbstractContentProviderStub.java │ │ │ │ ├── AbstractServiceStub.java │ │ │ │ ├── ActivityStub.java │ │ │ │ ├── ContentProviderStub.java │ │ │ │ ├── MyFakeIBinder.java │ │ │ │ ├── ServcesManager.java │ │ │ │ ├── ServiceStub.java │ │ │ │ └── ShortcutProxyActivity.java │ │ │ └── helper/ │ │ │ ├── AttributeCache.java │ │ │ ├── ComponentNameComparator.java │ │ │ ├── Log.java │ │ │ ├── MyProxy.java │ │ │ ├── Utils.java │ │ │ ├── compat/ │ │ │ │ ├── ActivityManagerCompat.java │ │ │ │ ├── ActivityManagerNativeCompat.java │ │ │ │ ├── ActivityThreadCompat.java │ │ │ │ ├── BuildCompat.java │ │ │ │ ├── BundleCompat.java │ │ │ │ ├── CompatibilityInfoCompat.java │ │ │ │ ├── ContentProviderCompat.java │ │ │ │ ├── ContentProviderHolderCompat.java │ │ │ │ ├── IActivityManagerCompat.java │ │ │ │ ├── IAppOpsServiceCompat.java │ │ │ │ ├── IAudioServiceCompat.java │ │ │ │ ├── IClipboardCompat.java │ │ │ │ ├── IContentServiceCompat.java │ │ │ │ ├── IDisplayManagerCompat.java │ │ │ │ ├── IGraphicsStatsCompat.java │ │ │ │ ├── IInputMethodManagerCompat.java │ │ │ │ ├── ILocationManagerCompat.java │ │ │ │ ├── IMediaRouterServiceCompat.java │ │ │ │ ├── IMmsCompat.java │ │ │ │ ├── IMountServiceCompat.java │ │ │ │ ├── INotificationManagerCompat.java │ │ │ │ ├── IPackageDataObserverCompat.java │ │ │ │ ├── IPhoneSubInfoCompat.java │ │ │ │ ├── ISearchManagerCompat.java │ │ │ │ ├── ISessionManagerCompat.java │ │ │ │ ├── ISmsCompat.java │ │ │ │ ├── ISubCompat.java │ │ │ │ ├── ITelephonyCompat.java │ │ │ │ ├── ITelephonyRegistryCompat.java │ │ │ │ ├── IWifiManagerCompat.java │ │ │ │ ├── IWindowManagerCompat.java │ │ │ │ ├── NativeLibraryHelperCompat.java │ │ │ │ ├── PackageManagerCompat.java │ │ │ │ ├── ParceledListSliceCompat.java │ │ │ │ ├── ProcessCompat.java │ │ │ │ ├── QueuedWorkCompat.java │ │ │ │ ├── ServiceManagerCompat.java │ │ │ │ ├── SingletonCompat.java │ │ │ │ ├── SystemPropertiesCompat.java │ │ │ │ ├── UserHandleCompat.java │ │ │ │ ├── VMRuntimeCompat.java │ │ │ │ └── WebViewFactoryCompat.java │ │ │ └── utils/ │ │ │ └── ProcessUtils.java │ │ └── res/ │ │ ├── drawable-xxhdpi/ │ │ │ └── plugin_activity_loading.xml │ │ ├── values/ │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v11/ │ │ │ └── styles.xml │ │ └── values-v14/ │ │ └── styles.xml │ ├── Test/ │ │ └── ApiTest/ │ │ ├── build.gradle │ │ ├── lib/ │ │ │ └── dalviksystem.jar │ │ ├── proguard-project.txt │ │ ├── project.properties │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── cpp/ │ │ │ ├── Core.cpp │ │ │ ├── HelperJni/ │ │ │ │ ├── HelperJni.cpp │ │ │ │ └── HelperJni.h │ │ │ └── help/ │ │ │ ├── log.h │ │ │ └── nativehelper/ │ │ │ ├── JNIHelp.cpp │ │ │ └── JNIHelp.h │ │ ├── java/ │ │ │ └── com/ │ │ │ ├── example/ │ │ │ │ └── ApiTest/ │ │ │ │ ├── ActivityTestActivity.java │ │ │ │ ├── BaseService.java │ │ │ │ ├── Binder1.aidl │ │ │ │ ├── Binder2.aidl │ │ │ │ ├── BroadcastReceiverTest.java │ │ │ │ ├── ContentProviderTest.java │ │ │ │ ├── ContentProviderTest2.java │ │ │ │ ├── LaunchModeTestActivity.java │ │ │ │ ├── MyActivity.java │ │ │ │ ├── MyContentProvider1.java │ │ │ │ ├── MyContentProvider2.java │ │ │ │ ├── NativeTestActivity.java │ │ │ │ ├── NotificationTest.java │ │ │ │ ├── Service1.java │ │ │ │ ├── Service2.java │ │ │ │ ├── Service3.java │ │ │ │ ├── Service4.java │ │ │ │ ├── ServiceTest1.java │ │ │ │ ├── ServiceTest2.java │ │ │ │ ├── SingleInstanceActivity.java │ │ │ │ ├── SingleTaskActivity.java │ │ │ │ ├── SingleTopActivity.java │ │ │ │ ├── StandardActivity.java │ │ │ │ ├── StaticBroadcastReceiver.java │ │ │ │ └── WebViewTestActivity.java │ │ │ └── morgoo/ │ │ │ └── nativec/ │ │ │ └── NativeCHelper.java │ │ └── res/ │ │ ├── layout/ │ │ │ ├── activity_activity_test.xml │ │ │ ├── activity_launchmode.xml │ │ │ ├── activity_native_test.xml │ │ │ ├── activity_web_view_test.xml │ │ │ ├── broadcast_receiver.xml │ │ │ ├── content_provider.xml │ │ │ ├── main.xml │ │ │ ├── notification_test.xml │ │ │ └── service.xml │ │ ├── values/ │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v11/ │ │ │ └── styles.xml │ │ ├── values-v14/ │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ ├── TestPlugin/ │ │ ├── build.gradle │ │ ├── proguard-project.txt │ │ ├── project.properties │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── TestPlugin/ │ │ │ ├── ApkFragment.java │ │ │ ├── ApkItem.java │ │ │ ├── InstalledFragment.java │ │ │ ├── MainActivity.java │ │ │ └── MyActivity.java │ │ └── res/ │ │ ├── layout/ │ │ │ ├── apk_item.xml │ │ │ └── main.xml │ │ ├── values/ │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v11/ │ │ │ └── styles.xml │ │ └── values-v14/ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── readme.md └── readme_cn.md
Showing preview only (211K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2197 symbols across 192 files)
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/MyCrashHandler.java
class MyCrashHandler (line 44) | public class MyCrashHandler implements UncaughtExceptionHandler {
method getInstance (line 59) | public static MyCrashHandler getInstance() {
method register (line 63) | public void register(Context context) {
method uncaughtException (line 73) | @Override
method getIMEI (line 162) | private String getIMEI(Context mContext) {
method getProcessName (line 166) | public String getProcessName() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/PluginApplication.java
class PluginApplication (line 31) | public class PluginApplication extends Application {
method onCreate (line 35) | @Override
method attachBaseContext (line 42) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/PluginHelper.java
class PluginHelper (line 46) | public class PluginHelper implements ServiceConnection {
method PluginHelper (line 52) | private PluginHelper() {
method getInstance (line 55) | public static final PluginHelper getInstance() {
method applicationOnCreate (line 62) | public void applicationOnCreate(final Context baseContext) {
method initPlugin (line 69) | private void initPlugin(Context baseContext) {
method fixMiUiLbeSecurity (line 109) | private void fixMiUiLbeSecurity() throws ClassNotFoundException, NoSuc...
method findLbeMessageAndRemoveIt (line 153) | private void findLbeMessageAndRemoveIt(Message message) {
method onServiceConnected (line 176) | @Override
method onServiceDisconnected (line 181) | @Override
method applicationAttachBaseContext (line 185) | public void applicationAttachBaseContext(Context baseContext) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/PluginManagerService.java
class PluginManagerService (line 40) | public class PluginManagerService extends Service {
method getPluginPackageManager (line 45) | public static IPluginManagerImpl getPluginPackageManager(Context conte...
method onCreate (line 57) | @Override
method keepAlive (line 64) | private void keepAlive() {
method onDestroy (line 75) | @Override
method onBind (line 85) | @Override
method onStartCommand (line 90) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/PluginPatchManager.java
class PluginPatchManager (line 16) | public class PluginPatchManager {
method getInstance (line 29) | public static PluginPatchManager getInstance() {
method init (line 33) | public void init(Context context){
method canStartPluginActivity (line 38) | public boolean canStartPluginActivity(Intent intent) {
method startPluginActivity (line 49) | public boolean startPluginActivity(Intent intent) {
method postDelayImpl (line 67) | private void postDelayImpl() {
method initInner (line 78) | private void initInner() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/PluginServiceProvider.java
class PluginServiceProvider (line 12) | public class PluginServiceProvider extends ContentProvider {
method onCreate (line 13) | @Override
method query (line 18) | @Override
method getType (line 23) | @Override
method insert (line 28) | @Override
method delete (line 33) | @Override
method update (line 38) | @Override
method call (line 43) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/BaseActivityManagerService.java
class BaseActivityManagerService (line 44) | public abstract class BaseActivityManagerService {
method BaseActivityManagerService (line 49) | public BaseActivityManagerService(Context hostContext) {
method getPackageNamesByPid (line 54) | public abstract List<String> getPackageNamesByPid(int pid);
method selectStubActivityInfo (line 56) | public abstract ActivityInfo selectStubActivityInfo(int callingPid, in...
method selectStubServiceInfo (line 58) | public abstract ServiceInfo selectStubServiceInfo(int callingPid, int ...
method getTargetServiceInfo (line 60) | public abstract ServiceInfo getTargetServiceInfo(int callingPid, int c...
method selectStubProviderInfo (line 62) | public abstract ProviderInfo selectStubProviderInfo(int callingPid, in...
method onPkgDeleted (line 64) | public void onPkgDeleted(Map<String, PluginPackageParser> pluginCache,...
method onPkgInstalled (line 67) | public void onPkgInstalled(Map<String, PluginPackageParser> pluginCach...
method onCreate (line 70) | public void onCreate(IPluginManagerImpl pluginManagerImpl) throws Exce...
method getProcessNameByPid (line 78) | public String getProcessNameByPid(int pid) {
method onReportMyProcessName (line 82) | public void onReportMyProcessName(int callingPid, int callingUid, Stri...
method onActivityOnNewIntent (line 85) | public abstract void onActivityOnNewIntent(int callingPid, int calling...
class ProcessCookie (line 87) | private static class ProcessCookie {
method ProcessCookie (line 88) | private ProcessCookie(int pid, int uid) {
class MyRemoteCallbackList (line 97) | private class MyRemoteCallbackList extends RemoteCallbackList<IApplica...
method onCallbackDied (line 98) | @Override
method onProcessDied (line 109) | protected void onProcessDied(int pid, int uid) {
method sendCallBack (line 113) | protected void sendCallBack(Bundle extra) {
method registerApplicationCallback (line 129) | public boolean registerApplicationCallback(int callingPid, int calling...
method unregisterApplicationCallback (line 133) | public boolean unregisterApplicationCallback(int callingPid, int calli...
method onActivityCreated (line 137) | public void onActivityCreated(int callingPid, int callingUid, Activity...
method onActivityDestroy (line 140) | public void onActivityDestroy(int callingPid, int callingUid, Activity...
method onServiceCreated (line 143) | public void onServiceCreated(int callingPid, int callingUid, ServiceIn...
method onServiceDestroy (line 146) | public void onServiceDestroy(int callingPid, int callingUid, ServiceIn...
method onProviderCreated (line 149) | public void onProviderCreated(int callingPid, int callingUid, Provider...
method onDestroy (line 152) | public void onDestroy() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/MyActivityManagerService.java
class MyActivityManagerService (line 58) | public class MyActivityManagerService extends BaseActivityManagerService {
method MyActivityManagerService (line 64) | public MyActivityManagerService(Context hostContext) {
method onCreate (line 69) | @Override
method onDestroy (line 77) | @Override
method onProcessDied (line 85) | @Override
method registerApplicationCallback (line 92) | @Override
method selectStubProviderInfo (line 111) | @Override
method getTargetServiceInfo (line 164) | @Override
method getProcessNameByPid (line 170) | @Override
method selectStubServiceInfo (line 175) | @Override
method throwException (line 227) | private RemoteException throwException(String msg) {
method onActivityCreated (line 234) | @Override
method onActivityDestroy (line 239) | @Override
method onActivityOnNewIntent (line 245) | @Override
method onServiceCreated (line 250) | @Override
method onServiceDestroy (line 255) | @Override
method onProviderCreated (line 261) | @Override
method onReportMyProcessName (line 266) | @Override
method getPackageNamesByPid (line 271) | @Override
method selectStubActivityInfo (line 276) | @Override
method compare (line 383) | @Override
method runProcessGC (line 396) | private void runProcessGC() {
method doGc (line 446) | private void doGc(RunningAppProcessInfo myInfo) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/RunningActivities.java
class RunningActivities (line 23) | public class RunningActivities {
method onActivtyOnNewIntent (line 32) | public static void onActivtyOnNewIntent(Activity activity, ActivityInf...
class RunningActivityRecord (line 37) | private static class RunningActivityRecord {
method RunningActivityRecord (line 43) | private RunningActivityRecord(Activity activity, ActivityInfo target...
method onActivtyCreate (line 52) | public static void onActivtyCreate(Activity activity, ActivityInfo tar...
method onActivtyDestory (line 68) | public static void onActivtyDestory(Activity activity) {
method beforeStartActivity (line 87) | public static void beforeStartActivity() {
method compare (line 104) | @Override
method doFinshIt (line 124) | private static void doFinshIt(Map<Integer, RunningActivityRecord> runn...
method findMaxIndex (line 148) | private static int findMaxIndex() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/RunningProcessList.java
class RunningProcessList (line 53) | class RunningProcessList {
method compare (line 58) | @Override
method compare (line 65) | @Override
method getStubProcessByTarget (line 71) | public String getStubProcessByTarget(ComponentInfo targetInfo) {
method isPersistentApplication (line 95) | public boolean isPersistentApplication(int pid) {
method isPersistentApp (line 143) | private boolean isPersistentApp(String packageName) {
method setContext (line 161) | public void setContext(Context context) {
class ProcessItem (line 171) | private class ProcessItem {
method updatePkgs (line 209) | private void updatePkgs() {
method addActivityInfo (line 227) | private void addActivityInfo(String stubActivityName, ActivityInfo i...
method removeActivityInfo (line 248) | void removeActivityInfo(String stubActivityName, ActivityInfo target...
method addServiceInfo (line 265) | private void addServiceInfo(String stubServiceName, ServiceInfo info) {
method removeServiceInfo (line 285) | void removeServiceInfo(String stubServiceName, ServiceInfo targetInf...
method addProviderInfo (line 302) | private void addProviderInfo(String stubAuthority, ProviderInfo info) {
method removeProviderInfo (line 322) | void removeProviderInfo(String stubAuthority, ProviderInfo targetInf...
method removeByPid (line 345) | ProcessItem removeByPid(int pid) {
method getStubServiceByPid (line 349) | List<String> getStubServiceByPid(int pid) {
method addActivityInfo (line 358) | void addActivityInfo(int pid, int uid, ActivityInfo stubInfo, Activity...
method removeActivityInfo (line 377) | void removeActivityInfo(int pid, int uid, ActivityInfo stubInfo, Activ...
method addServiceInfo (line 388) | void addServiceInfo(int pid, int uid, ServiceInfo stubInfo, ServiceInf...
method removeServiceInfo (line 408) | void removeServiceInfo(int pid, int uid, ServiceInfo stubInfo, Service...
method addProviderInfo (line 423) | void addProviderInfo(int pid, int uid, ProviderInfo stubInfo, Provider...
method addItem (line 442) | void addItem(int pid, int uid) {
method isProcessRunning (line 457) | boolean isProcessRunning(String stubProcessName) {
method isPkgCanRunInProcess (line 467) | boolean isPkgCanRunInProcess(String packageName, String stubProcessNam...
method isPkgEmpty (line 494) | boolean isPkgEmpty(String stubProcessName) {
method isStubInfoUsed (line 504) | boolean isStubInfoUsed(ProviderInfo stubInfo) {
method isStubInfoUsed (line 509) | boolean isStubInfoUsed(ServiceInfo stubInfo) {
method isStubInfoUsed (line 514) | boolean isStubInfoUsed(ActivityInfo stubInfo, ActivityInfo targetInfo,...
method getPackageNameByPid (line 533) | List<String> getPackageNameByPid(int pid) {
method getTargetProcessNameByPid (line 538) | String getTargetProcessNameByPid(int pid) {
method getStubProcessNameByPid (line 543) | public String getStubProcessNameByPid(int pid) {
method setTargetProcessName (line 548) | void setTargetProcessName(ComponentInfo stubInfo, ComponentInfo target...
method getActivityCountByPid (line 559) | int getActivityCountByPid(int pid) {
method getServiceCountByPid (line 564) | int getServiceCountByPid(int pid) {
method getProviderCountByPid (line 569) | int getProviderCountByPid(int pid) {
method setProcessName (line 574) | void setProcessName(int pid, String stubProcessName, String targetProc...
method onProcessDied (line 585) | void onProcessDied(int pid, int uid) {
method clear (line 590) | void clear() {
method isPlugin (line 594) | boolean isPlugin(int pid) {
method dump (line 602) | void dump(String msg) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/ServiceStubMap.java
class ServiceStubMap (line 37) | class ServiceStubMap {
class MyServiceInfo (line 40) | private static class MyServiceInfo implements Comparable<MyServiceInfo> {
method MyServiceInfo (line 43) | MyServiceInfo(ServiceInfo info) {
method equals (line 47) | @Override
method compareTo (line 57) | @Override
method getPluginInfosByStub (line 66) | List<ServiceInfo> getPluginInfosByStub(ServiceInfo stubInfo) {
method getStubInfoByPlugin (line 80) | ServiceInfo getStubInfoByPlugin(ServiceInfo pluginInfo) {
method addToMap (line 91) | void addToMap(ServiceInfo stubInfo, ServiceInfo pluginInfo) {
method removeFormMap (line 102) | void removeFormMap(ServiceInfo pluginInfo) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/StaticProcessList.java
class StaticProcessList (line 52) | class StaticProcessList {
class ProcessItem (line 68) | private class ProcessItem {
method addActivityInfo (line 79) | private void addActivityInfo(ActivityInfo info) {
method addServiceInfo (line 86) | private void addServiceInfo(ServiceInfo info) {
method addProviderInfo (line 93) | private void addProviderInfo(ProviderInfo info) {
method onCreate (line 101) | void onCreate(Context mHostContext) throws NameNotFoundException {
method getOtherProcessNames (line 165) | public List<String> getOtherProcessNames() {
method addActivityInfo (line 169) | private void addActivityInfo(ActivityInfo info) {
method findActivityInfoForName (line 182) | ActivityInfo findActivityInfoForName(String processName, String activi...
method findActivityInfoForLaunchMode (line 190) | ActivityInfo findActivityInfoForLaunchMode(String processName, int lau...
method addServiceInfo (line 203) | private void addServiceInfo(ServiceInfo info) {
method findServiceInfoForName (line 216) | ServiceInfo findServiceInfoForName(String processName, String serviceI...
method addProviderInfo (line 225) | private void addProviderInfo(ProviderInfo info) {
method findProviderInfoForAuthority (line 238) | ProviderInfo findProviderInfoForAuthority(String processName, String a...
method getProcessNames (line 246) | List<String> getProcessNames() {
method getActivityInfoForProcessName (line 250) | List<ActivityInfo> getActivityInfoForProcessName(String processName) {
method compare (line 259) | @Override
method getActivityInfoForProcessName (line 265) | List<ActivityInfo> getActivityInfoForProcessName(String processName, b...
method getServiceInfoForProcessName (line 286) | List<ServiceInfo> getServiceInfoForProcessName(String processName) {
method getProviderInfoForProcessName (line 293) | List<ProviderInfo> getProviderInfoForProcessName(String processName) {
method clear (line 300) | void clear() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/core/Env.java
class Env (line 28) | public class Env {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/core/PluginClassLoader.java
class PluginClassLoader (line 37) | public class PluginClassLoader extends DexClassLoader {
method PluginClassLoader (line 39) | public PluginClassLoader(String apkfile, String optimizedDirectory, St...
method loadClass (line 49) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/core/PluginDirHelper.java
class PluginDirHelper (line 42) | public class PluginDirHelper {
method init (line 47) | private static void init(Context context) {
method enforceDirExists (line 54) | private static String enforceDirExists(File file) {
method makePluginBaseDir (line 61) | public static String makePluginBaseDir(Context context, String pluginI...
method getBaseDir (line 66) | public static String getBaseDir(Context context) {
method getPluginDataDir (line 71) | public static String getPluginDataDir(Context context, String pluginIn...
method getPluginSignatureDir (line 75) | public static String getPluginSignatureDir(Context context, String plu...
method getPluginSignatureFile (line 79) | public static String getPluginSignatureFile(Context context, String pl...
method getPluginSignatureFiles (line 83) | public static List<String> getPluginSignatureFiles(Context context, St...
method getPluginApkDir (line 96) | public static String getPluginApkDir(Context context, String pluginInf...
method getPluginApkFile (line 100) | public static String getPluginApkFile(Context context, String pluginIn...
method getPluginDalvikCacheDir (line 104) | public static String getPluginDalvikCacheDir(Context context, String p...
method getPluginNativeLibraryDir (line 108) | public static String getPluginNativeLibraryDir(Context context, String...
method getPluginDalvikCacheFile (line 113) | public static String getPluginDalvikCacheFile(Context context, String ...
method getContextDataDir (line 125) | public static String getContextDataDir(Context context) {
method cleanOptimizedDirectory (line 130) | public static void cleanOptimizedDirectory(String optimizedDirectory) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/core/PluginProcessManager.java
class PluginProcessManager (line 70) | public class PluginProcessManager {
method getCurrentProcessName (line 80) | public static String getCurrentProcessName(Context context) {
method initProcessList (line 105) | private static void initProcessList(Context context) {
method isPluginProcess (line 151) | public static final boolean isPluginProcess(Context context) {
method getPluginClassLoader (line 160) | public static ClassLoader getPluginClassLoader(String pkg) throws Ille...
method preLoadApk (line 172) | public static void preLoadApk(Context hostContext, ComponentInfo plugi...
method preMakeApplication (line 235) | private static void preMakeApplication(Context hostContext, ComponentI...
method registerStaticReceiver (line 280) | public static void registerStaticReceiver(Context context, Application...
method setHookEnable (line 304) | public static void setHookEnable(boolean enable) {
method setHookEnable (line 308) | public static void setHookEnable(boolean enable, boolean reinstallHook) {
method installHook (line 312) | public static void installHook(Context hostContext) throws Throwable {
method getPluginContext (line 318) | public static Application getPluginContext(String packageName) throws ...
method getBaseContext (line 338) | private static Context getBaseContext(Context c) {
method fakeSystemServiceInner (line 376) | private static void fakeSystemServiceInner(Context hostContext, Contex...
method fakeSystemService (line 461) | public static void fakeSystemService(Context hostContext, Context targ...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/BaseHookHandle.java
class BaseHookHandle (line 38) | public abstract class BaseHookHandle {
method BaseHookHandle (line 44) | public BaseHookHandle(Context hostContext) {
method init (line 49) | protected abstract void init();
method getHookedMethodNames (line 51) | public Set<String> getHookedMethodNames(){
method getHookedMethodHandler (line 55) | public HookedMethodHandler getHookedMethodHandler(Method method) {
method getHookedClass (line 63) | protected Class<?> getHookedClass() throws ClassNotFoundException {
method newBaseHandler (line 67) | protected HookedMethodHandler newBaseHandler() throws ClassNotFoundExc...
method addAllMethodFromHookedClass (line 71) | protected void addAllMethodFromHookedClass(){
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/Hook.java
class Hook (line 30) | public abstract class Hook {
method setEnable (line 37) | public void setEnable(boolean enable, boolean reInstallHook) {
method setEnable (line 41) | public final void setEnable(boolean enable) {
method isEnable (line 45) | public boolean isEnable() {
method Hook (line 50) | protected Hook(Context hostContext) {
method createHookHandle (line 55) | protected abstract BaseHookHandle createHookHandle();
method onInstall (line 58) | protected abstract void onInstall(ClassLoader classLoader) throws Thro...
method onUnInstall (line 60) | protected void onUnInstall(ClassLoader classLoader) throws Throwable {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/HookFactory.java
class HookFactory (line 67) | public class HookFactory {
method HookFactory (line 72) | private HookFactory() {
method getInstance (line 75) | public static HookFactory getInstance() {
method setHookEnable (line 87) | public void setHookEnable(boolean enable) {
method setHookEnable (line 95) | public void setHookEnable(boolean enable, boolean reinstallHook) {
method setHookEnable (line 103) | public void setHookEnable(Class hookClass, boolean enable) {
method installHook (line 113) | public void installHook(Hook hook, ClassLoader cl) {
method installHook (line 125) | public final void installHook(Context context, ClassLoader classLoader...
method onCallApplicationOnCreate (line 201) | public final void onCallApplicationOnCreate(Context context, Applicati...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/HookedMethodHandler.java
class HookedMethodHandler (line 30) | public class HookedMethodHandler {
method HookedMethodHandler (line 38) | public HookedMethodHandler(Context hostContext) {
method doHookInner (line 43) | public synchronized Object doHookInner(Object receiver, Method method,...
method setFakedResult (line 67) | public void setFakedResult(Object fakedResult) {
method beforeInvoke (line 75) | protected boolean beforeInvoke(Object receiver, Method method, Object[...
method afterInvoke (line 79) | protected void afterInvoke(Object receiver, Method method, Object[] ar...
method isFakedResult (line 82) | public boolean isFakedResult() {
method getFakedResult (line 86) | public Object getFakedResult() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/BinderHook.java
class BinderHook (line 42) | abstract class BinderHook extends Hook implements InvocationHandler {
method BinderHook (line 46) | public BinderHook(Context hostContext) {
method invoke (line 50) | @Override
method getOldObj (line 107) | abstract Object getOldObj() throws Exception;
method setOldObj (line 109) | void setOldObj(Object mOldObj) {
method getServiceName (line 113) | public abstract String getServiceName();
method onInstall (line 115) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IAppOpsServiceBinderHook.java
class IAppOpsServiceBinderHook (line 34) | public class IAppOpsServiceBinderHook extends BinderHook{
method IAppOpsServiceBinderHook (line 38) | public IAppOpsServiceBinderHook(Context hostContext) {
method getOldObj (line 42) | @Override
method getServiceName (line 48) | @Override
method createHookHandle (line 53) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IAudioServiceBinderHook.java
class IAudioServiceBinderHook (line 35) | public class IAudioServiceBinderHook extends BinderHook {
method IAudioServiceBinderHook (line 39) | public IAudioServiceBinderHook(Context hostContext) {
method getOldObj (line 43) | @Override
method getServiceName (line 49) | @Override
method createHookHandle (line 54) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IClipboardBinderHook.java
class IClipboardBinderHook (line 34) | public class IClipboardBinderHook extends BinderHook {
method IClipboardBinderHook (line 38) | public IClipboardBinderHook(Context hostContext) {
method getOldObj (line 42) | @Override
method getServiceName (line 48) | @Override
method createHookHandle (line 53) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IContentServiceBinderHook.java
class IContentServiceBinderHook (line 35) | public class IContentServiceBinderHook extends BinderHook {
method IContentServiceBinderHook (line 39) | public IContentServiceBinderHook(Context hostContext) {
method getOldObj (line 43) | @Override
method getServiceName (line 49) | @Override
method createHookHandle (line 54) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IDisplayManagerBinderHook.java
class IDisplayManagerBinderHook (line 18) | public class IDisplayManagerBinderHook extends BinderHook {
method IDisplayManagerBinderHook (line 23) | public IDisplayManagerBinderHook(Context hostContext) {
method getServiceName (line 27) | @Override
method getOldObj (line 32) | @Override
method onInstall (line 38) | @Override
method createHookHandle (line 46) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IGraphicsStatsBinderHook.java
class IGraphicsStatsBinderHook (line 37) | public class IGraphicsStatsBinderHook extends BinderHook {
method IGraphicsStatsBinderHook (line 41) | public IGraphicsStatsBinderHook(Context hostContext) {
method getOldObj (line 45) | @Override
method getServiceName (line 51) | @Override
method createHookHandle (line 56) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IInputMethodManagerBinderHook.java
class IInputMethodManagerBinderHook (line 39) | public class IInputMethodManagerBinderHook extends BinderHook {
method IInputMethodManagerBinderHook (line 43) | public IInputMethodManagerBinderHook(Context hostContext) {
method getOldObj (line 47) | @Override
method onInstall (line 53) | @Override
method getServiceName (line 63) | @Override
method createHookHandle (line 68) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ILocationManagerBinderHook.java
class ILocationManagerBinderHook (line 35) | public class ILocationManagerBinderHook extends BinderHook {
method ILocationManagerBinderHook (line 40) | public ILocationManagerBinderHook(Context hostContext) {
method getOldObj (line 44) | @Override
method getServiceName (line 50) | @Override
method createHookHandle (line 55) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IMediaRouterServiceBinderHook.java
class IMediaRouterServiceBinderHook (line 34) | public class IMediaRouterServiceBinderHook extends BinderHook {
method IMediaRouterServiceBinderHook (line 37) | public IMediaRouterServiceBinderHook(Context hostContext) {
method getOldObj (line 41) | @Override
method getServiceName (line 47) | @Override
method createHookHandle (line 52) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IMmsBinderHook.java
class IMmsBinderHook (line 34) | public class IMmsBinderHook extends BinderHook {
method IMmsBinderHook (line 38) | public IMmsBinderHook(Context hostContext) {
method getOldObj (line 42) | @Override
method getServiceName (line 48) | @Override
method createHookHandle (line 53) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IMountServiceBinderHook.java
class IMountServiceBinderHook (line 34) | public class IMountServiceBinderHook extends BinderHook {
method IMountServiceBinderHook (line 38) | public IMountServiceBinderHook(Context hostContext) {
method getOldObj (line 42) | @Override
method getServiceName (line 48) | @Override
method createHookHandle (line 53) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/INotificationManagerBinderHook.java
class INotificationManagerBinderHook (line 34) | public class INotificationManagerBinderHook extends BinderHook {
method INotificationManagerBinderHook (line 38) | public INotificationManagerBinderHook(Context hostContext) {
method createHookHandle (line 42) | @Override
method getOldObj (line 47) | public Object getOldObj() throws Exception{
method getServiceName (line 52) | public String getServiceName() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IPhoneSubInfoBinderHook.java
class IPhoneSubInfoBinderHook (line 35) | public class IPhoneSubInfoBinderHook extends BinderHook {
method IPhoneSubInfoBinderHook (line 39) | public IPhoneSubInfoBinderHook(Context hostContext) {
method getOldObj (line 43) | @Override
method getServiceName (line 49) | @Override
method createHookHandle (line 54) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ISearchManagerBinderHook.java
class ISearchManagerBinderHook (line 35) | public class ISearchManagerBinderHook extends BinderHook {
method ISearchManagerBinderHook (line 39) | public ISearchManagerBinderHook(Context hostContext) {
method getOldObj (line 43) | @Override
method getServiceName (line 49) | @Override
method createHookHandle (line 54) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ISessionManagerBinderHook.java
class ISessionManagerBinderHook (line 34) | public class ISessionManagerBinderHook extends BinderHook {
method ISessionManagerBinderHook (line 37) | public ISessionManagerBinderHook(Context hostContext) {
method getOldObj (line 41) | @Override
method getServiceName (line 47) | @Override
method createHookHandle (line 52) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ISmsBinderHook.java
class ISmsBinderHook (line 34) | public class ISmsBinderHook extends BinderHook {
method ISmsBinderHook (line 38) | public ISmsBinderHook(Context hostContext) {
method getOldObj (line 42) | @Override
method getServiceName (line 48) | @Override
method createHookHandle (line 53) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ISubBinderHook.java
class ISubBinderHook (line 35) | public class ISubBinderHook extends BinderHook {
method ISubBinderHook (line 40) | public ISubBinderHook(Context hostContext) {
method getOldObj (line 44) | @Override
method getServiceName (line 50) | @Override
method createHookHandle (line 55) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ITelephonyBinderHook.java
class ITelephonyBinderHook (line 34) | public class ITelephonyBinderHook extends BinderHook {
method ITelephonyBinderHook (line 36) | public ITelephonyBinderHook(Context hostContext) {
method getOldObj (line 43) | @Override
method getServiceName (line 49) | @Override
method createHookHandle (line 54) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ITelephonyRegistryBinderHook.java
class ITelephonyRegistryBinderHook (line 34) | public class ITelephonyRegistryBinderHook extends BinderHook {
method ITelephonyRegistryBinderHook (line 38) | public ITelephonyRegistryBinderHook(Context hostContext) {
method getOldObj (line 42) | @Override
method getServiceName (line 48) | @Override
method createHookHandle (line 53) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IWifiManagerBinderHook.java
class IWifiManagerBinderHook (line 38) | public class IWifiManagerBinderHook extends BinderHook {
method IWifiManagerBinderHook (line 44) | public IWifiManagerBinderHook(Context hostContext) {
method getOldObj (line 48) | @Override
method getServiceName (line 54) | @Override
method createHookHandle (line 59) | @Override
method onInstall (line 64) | @Override
method fixZTESecurity (line 71) | private void fixZTESecurity() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IWindowManagerBinderHook.java
class IWindowManagerBinderHook (line 43) | public class IWindowManagerBinderHook extends BinderHook {
method IWindowManagerBinderHook (line 48) | public IWindowManagerBinderHook(Context hostContext) {
method getOldObj (line 52) | @Override
method getServiceName (line 58) | @Override
method createHookHandle (line 63) | @Override
method onInstall (line 68) | @Override
method fixWindowManagerHook (line 79) | public static void fixWindowManagerHook(Activity activity) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/MyServiceManager.java
class MyServiceManager (line 33) | public class MyServiceManager {
method getOriginService (line 39) | static IBinder getOriginService(String serviceName) {
method addOriginService (line 43) | public static void addOriginService(String serviceName, IBinder servic...
method addProxiedServiceCache (line 47) | static void addProxiedServiceCache(String serviceName, IBinder proxyS...
method getProxiedObj (line 51) | static Object getProxiedObj(String servicename) {
method addProxiedObj (line 55) | static void addProxiedObj(String servicename, Object obj) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ServiceManagerBinderHook.java
class ServiceManagerBinderHook (line 45) | public class ServiceManagerBinderHook extends ProxyHook implements Invoc...
method ServiceManagerBinderHook (line 47) | public ServiceManagerBinderHook(Context hostContext) {
method onInstall (line 53) | @Override
class ServiceManagerHookHandle (line 69) | private class ServiceManagerHookHandle extends BaseHookHandle {
method ServiceManagerHookHandle (line 71) | private ServiceManagerHookHandle(Context context) {
method init (line 75) | @Override
class ServiceManagerHook (line 81) | private class ServiceManagerHook extends HookedMethodHandler {
method ServiceManagerHook (line 82) | public ServiceManagerHook(Context hostContext) {
method afterInvoke (line 86) | @Override
class getService (line 101) | private class getService extends ServiceManagerHook {
method getService (line 102) | public getService(Context hostContext) {
class checkService (line 107) | private class checkService extends ServiceManagerHook {
method checkService (line 108) | public checkService(Context hostContext) {
method createHookHandle (line 114) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ServiceManagerCacheBinderHook.java
class ServiceManagerCacheBinderHook (line 48) | public class ServiceManagerCacheBinderHook extends Hook implements Invoc...
method ServiceManagerCacheBinderHook (line 53) | public ServiceManagerCacheBinderHook(Context hostContext, String servi...
method onInstall (line 60) | @Override
method invoke (line 92) | @Override
class ServiceManagerHookHandle (line 150) | private class ServiceManagerHookHandle extends BaseHookHandle {
method ServiceManagerHookHandle (line 152) | private ServiceManagerHookHandle(Context context) {
method init (line 156) | @Override
class queryLocalInterface (line 162) | class queryLocalInterface extends HookedMethodHandler {
method queryLocalInterface (line 163) | public queryLocalInterface(Context context) {
method afterInvoke (line 167) | @Override
method createHookHandle (line 178) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IActivityManagerHookHandle.java
class IActivityManagerHookHandle (line 80) | public class IActivityManagerHookHandle extends BaseHookHandle {
method IActivityManagerHookHandle (line 84) | public IActivityManagerHookHandle(Context hostContext) {
method init (line 88) | @Override
class startActivity (line 154) | private static class startActivity extends ReplaceCallingPackageHooked...
method startActivity (line 156) | public startActivity(Context hostContext) {
method doReplaceIntentForStartActivityAPIHigh (line 160) | protected boolean doReplaceIntentForStartActivityAPIHigh(Object[] ar...
method setIntentClassLoader (line 214) | private void setIntentClassLoader(Intent intent, ClassLoader classLo...
method doReplaceIntentForStartActivityAPILow (line 230) | protected boolean doReplaceIntentForStartActivityAPILow(Object[] arg...
method beforeInvoke (line 254) | @Override
class startActivityAsUser (line 302) | private static class startActivityAsUser extends startActivity {
method startActivityAsUser (line 304) | public startActivityAsUser(Context hostContext) {
class startActivityAsCaller (line 326) | private static class startActivityAsCaller extends startActivity {
method startActivityAsCaller (line 328) | public startActivityAsCaller(Context hostContext) {
method beforeInvoke (line 332) | @Override
class startActivityAndWait (line 342) | private static class startActivityAndWait extends startActivity {
method startActivityAndWait (line 344) | public startActivityAndWait(Context hostContext) {
class startActivityWithConfig (line 388) | private static class startActivityWithConfig extends startActivity {
method startActivityWithConfig (line 390) | public startActivityWithConfig(Context hostContext) {
class startActivityIntentSender (line 419) | private static class startActivityIntentSender extends ReplaceCallingP...
method startActivityIntentSender (line 421) | public startActivityIntentSender(Context hostContext) {
class startVoiceActivity (line 439) | private static class startVoiceActivity extends startActivity {
method startVoiceActivity (line 441) | public startVoiceActivity(Context hostContext) {
method beforeInvoke (line 445) | @Override
class startNextMatchingActivity (line 468) | private static class startNextMatchingActivity extends startActivity {
method startNextMatchingActivity (line 470) | public startNextMatchingActivity(Context hostContext) {
method beforeInvoke (line 474) | @Override
class startActivityFromRecents (line 488) | private static class startActivityFromRecents extends ReplaceCallingPa...
method startActivityFromRecents (line 490) | public startActivityFromRecents(Context hostContext) {
class finishActivity (line 499) | private static class finishActivity extends ReplaceCallingPackageHooke...
method finishActivity (line 501) | public finishActivity(Context hostContext) {
class registerReceiver (line 514) | private static class registerReceiver extends ReplaceCallingPackageHoo...
method registerReceiver (line 516) | public registerReceiver(Context hostContext) {
method beforeInvoke (line 520) | @Override
class broadcastIntent (line 552) | private static class broadcastIntent extends ReplaceCallingPackageHook...
method broadcastIntent (line 554) | public broadcastIntent(Context hostContext) {
method beforeInvoke (line 576) | @Override
method checkAndProcessIntent (line 586) | private boolean checkAndProcessIntent(Intent intent) throws RemoteEx...
method drawableToBitMap (line 650) | private Bitmap drawableToBitMap(Drawable drawable) {
class unbroadcastIntent (line 665) | private static class unbroadcastIntent extends ReplaceCallingPackageHo...
method unbroadcastIntent (line 667) | public unbroadcastIntent(Context hostContext) {
class getCallingPackage (line 678) | private static class getCallingPackage extends ReplaceCallingPackageHo...
method getCallingPackage (line 680) | public getCallingPackage(Context hostContext) {
class getCallingActivity (line 689) | private static class getCallingActivity extends ReplaceCallingPackageH...
method getCallingActivity (line 691) | public getCallingActivity(Context hostContext) {
class getAppTasks (line 701) | private static class getAppTasks extends ReplaceCallingPackageHookedMe...
method getAppTasks (line 703) | public getAppTasks(Context hostContext) {
class addAppTask (line 711) | private static class addAppTask extends ReplaceCallingPackageHookedMet...
method addAppTask (line 713) | public addAppTask(Context hostContext) {
class getTasks (line 723) | private static class getTasks extends ReplaceCallingPackageHookedMetho...
method getTasks (line 725) | public getTasks(Context hostContext) {
class getServices (line 755) | private static class getServices extends ReplaceCallingPackageHookedMe...
method getServices (line 757) | public getServices(Context hostContext) {
method afterInvoke (line 762) | @Override
class getProcessesInErrorState (line 780) | private static class getProcessesInErrorState extends ReplaceCallingPa...
method getProcessesInErrorState (line 782) | public getProcessesInErrorState(Context hostContext) {
class getContentProvider (line 792) | private static class getContentProvider extends ReplaceCallingPackageH...
method getContentProvider (line 794) | public getContentProvider(Context hostContext) {
method beforeInvoke (line 801) | @Override
method afterInvoke (line 832) | @Override
method copyField (line 881) | private void copyField(Object fromObj, Object toObj, String fieldNam...
method copyConnection (line 885) | @TargetApi(VERSION_CODES.JELLY_BEAN)
class getContentProviderExternal (line 891) | private static class getContentProviderExternal extends getContentProv...
method getContentProviderExternal (line 893) | public getContentProviderExternal(Context hostContext) {
class removeContentProviderExternal (line 905) | private static class removeContentProviderExternal extends ReplaceCall...
method removeContentProviderExternal (line 907) | public removeContentProviderExternal(Context hostContext) {
class publishContentProviders (line 916) | private static class publishContentProviders extends ReplaceCallingPac...
method publishContentProviders (line 918) | public publishContentProviders(Context hostContext) {
class getRunningServiceControlPanel (line 928) | private static class getRunningServiceControlPanel extends ReplaceCall...
method getRunningServiceControlPanel (line 930) | public getRunningServiceControlPanel(Context hostContext) {
class startService (line 941) | private static class startService extends ReplaceCallingPackageHookedM...
method startService (line 943) | public startService(Context hostContext) {
method beforeInvoke (line 949) | @Override
method afterInvoke (line 962) | @Override
class stopService (line 974) | private static class stopService extends ReplaceCallingPackageHookedMe...
method stopService (line 976) | public stopService(Context hostContext) {
method beforeInvoke (line 980) | @Override
class stopServiceToken (line 1003) | private static class stopServiceToken extends ReplaceCallingPackageHoo...
method stopServiceToken (line 1005) | public stopServiceToken(Context hostContext) {
method beforeInvoke (line 1009) | @Override
class setServiceForeground (line 1028) | private static class setServiceForeground extends ReplaceCallingPackag...
method setServiceForeground (line 1030) | public setServiceForeground(Context hostContext) {
method beforeInvoke (line 1034) | @Override
class bindService (line 1049) | private static class bindService extends ReplaceCallingPackageHookedMe...
method bindService (line 1051) | public bindService(Context hostContext) {
method beforeInvoke (line 1057) | @Override
method findIServiceConnectionIndex (line 1091) | private int findIServiceConnectionIndex(Method method) {
method afterInvoke (line 1103) | @Override
class MyIServiceConnection (line 1114) | private abstract static class MyIServiceConnection extends IServiceC...
method MyIServiceConnection (line 1117) | private MyIServiceConnection(ServiceInfo info) {
class publishService (line 1123) | private static class publishService extends ReplaceCallingPackageHooke...
method publishService (line 1125) | public publishService(Context hostContext) {
method beforeInvoke (line 1129) | @Override
class unbindFinished (line 1143) | private static class unbindFinished extends ReplaceCallingPackageHooke...
method unbindFinished (line 1145) | public unbindFinished(Context hostContext) {
method beforeInvoke (line 1149) | @Override
class peekService (line 1159) | private static class peekService extends ReplaceCallingPackageHookedMe...
method peekService (line 1161) | public peekService(Context hostContext) {
method beforeInvoke (line 1165) | @Override
class bindBackupAgent (line 1174) | private static class bindBackupAgent extends ReplaceCallingPackageHook...
method bindBackupAgent (line 1176) | public bindBackupAgent(Context hostContext) {
method beforeInvoke (line 1180) | @Override
class backupAgentCreated (line 1198) | private static class backupAgentCreated extends ReplaceCallingPackageH...
method backupAgentCreated (line 1200) | public backupAgentCreated(Context hostContext) {
method beforeInvoke (line 1204) | @Override
class unbindBackupAgent (line 1221) | private static class unbindBackupAgent extends ReplaceCallingPackageHo...
method unbindBackupAgent (line 1223) | public unbindBackupAgent(Context hostContext) {
method beforeInvoke (line 1227) | @Override
class killApplicationProcess (line 1244) | private static class killApplicationProcess extends ReplaceCallingPack...
method killApplicationProcess (line 1246) | public killApplicationProcess(Context hostContext) {
method beforeInvoke (line 1250) | @Override
class startInstrumentation (line 1272) | private static class startInstrumentation extends ReplaceCallingPackag...
method startInstrumentation (line 1274) | public startInstrumentation(Context hostContext) {
class getActivityClassForToken (line 1299) | private static class getActivityClassForToken extends ReplaceCallingPa...
method getActivityClassForToken (line 1301) | public getActivityClassForToken(Context hostContext) {
class getPackageForToken (line 1311) | private static class getPackageForToken extends ReplaceCallingPackageH...
method getPackageForToken (line 1313) | public getPackageForToken(Context hostContext) {
class getIntentSender (line 1323) | public static class getIntentSender extends ReplaceCallingPackageHooke...
method getIntentSender (line 1325) | public getIntentSender(Context hostContext) {
method beforeInvoke (line 1329) | @Override
method replace (line 1405) | private Intent replace(int type, Intent intent) throws RemoteExcepti...
method handlePendingIntent (line 1428) | public static void handlePendingIntent(final Context context, Intent...
class clearApplicationUserData (line 1494) | private static class clearApplicationUserData extends ReplaceCallingPa...
method clearApplicationUserData (line 1496) | public clearApplicationUserData(Context hostContext) {
method beforeInvoke (line 1500) | @Override
class handleIncomingUser (line 1523) | private static class handleIncomingUser extends ReplaceCallingPackageH...
method handleIncomingUser (line 1525) | public handleIncomingUser(Context hostContext) {
method beforeInvoke (line 1529) | @Override
class grantUriPermission (line 1551) | private static class grantUriPermission extends ReplaceCallingPackageH...
method grantUriPermission (line 1553) | public grantUriPermission(Context hostContext) {
method beforeInvoke (line 1557) | @Override
class getPersistedUriPermissions (line 1580) | private static class getPersistedUriPermissions extends ReplaceCalling...
method getPersistedUriPermissions (line 1582) | public getPersistedUriPermissions(Context hostContext) {
method beforeInvoke (line 1586) | @Override
class killBackgroundProcesses (line 1606) | private static class killBackgroundProcesses extends ReplaceCallingPac...
method killBackgroundProcesses (line 1608) | public killBackgroundProcesses(Context hostContext) {
method beforeInvoke (line 1612) | @Override
class forceStopPackage (line 1634) | private static class forceStopPackage extends ReplaceCallingPackageHoo...
method forceStopPackage (line 1636) | public forceStopPackage(Context hostContext) {
method beforeInvoke (line 1640) | @Override
class getRunningAppProcesses (line 1660) | private static class getRunningAppProcesses extends ReplaceCallingPack...
method getRunningAppProcesses (line 1662) | public getRunningAppProcesses(Context hostContext) {
method afterInvoke (line 1666) | @Override
class getRunningExternalApplications (line 1713) | private static class getRunningExternalApplications extends ReplaceCal...
method getRunningExternalApplications (line 1715) | public getRunningExternalApplications(Context hostContext) {
method afterInvoke (line 1719) | @Override
class getMyMemoryState (line 1756) | private static class getMyMemoryState extends ReplaceCallingPackageHoo...
method getMyMemoryState (line 1758) | public getMyMemoryState(Context hostContext) {
class crashApplication (line 1767) | private static class crashApplication extends ReplaceCallingPackageHoo...
method crashApplication (line 1769) | public crashApplication(Context hostContext) {
method beforeInvoke (line 1773) | @Override
class grantUriPermissionFromOwner (line 1793) | private static class grantUriPermissionFromOwner extends ReplaceCallin...
method grantUriPermissionFromOwner (line 1795) | public grantUriPermissionFromOwner(Context hostContext) {
method beforeInvoke (line 1799) | @Override
class checkGrantUriPermission (line 1820) | private static class checkGrantUriPermission extends ReplaceCallingPac...
method checkGrantUriPermission (line 1822) | public checkGrantUriPermission(Context hostContext) {
method beforeInvoke (line 1826) | @Override
class startActivities (line 1850) | private static class startActivities extends ReplaceCallingPackageHook...
method startActivities (line 1853) | public startActivities(Context hostContext) {
method beforeInvoke (line 1857) | @Override
class getPackageScreenCompatMode (line 1940) | private static class getPackageScreenCompatMode extends ReplaceCalling...
method getPackageScreenCompatMode (line 1942) | public getPackageScreenCompatMode(Context hostContext) {
method beforeInvoke (line 1946) | @Override
class setPackageScreenCompatMode (line 1967) | private static class setPackageScreenCompatMode extends ReplaceCalling...
method setPackageScreenCompatMode (line 1969) | public setPackageScreenCompatMode(Context hostContext) {
method beforeInvoke (line 1973) | @Override
class getPackageAskScreenCompat (line 1995) | private static class getPackageAskScreenCompat extends ReplaceCallingP...
method getPackageAskScreenCompat (line 1997) | public getPackageAskScreenCompat(Context hostContext) {
method beforeInvoke (line 2001) | @Override
class setPackageAskScreenCompat (line 2023) | private static class setPackageAskScreenCompat extends ReplaceCallingP...
method setPackageAskScreenCompat (line 2024) | public setPackageAskScreenCompat(Context hostContext) {
method beforeInvoke (line 2028) | @Override
class navigateUpTo (line 2051) | private static class navigateUpTo extends ReplaceCallingPackageHookedM...
method navigateUpTo (line 2052) | public navigateUpTo(Context hostContext) {
method replaceFirstServiceIntentOfArgs (line 2064) | private static ServiceInfo replaceFirstServiceIntentOfArgs(Object[] ar...
method findFirstIntentIndexInArgs (line 2091) | private static int findFirstIntentIndexInArgs(Object[] args) {
method selectProxyActivity (line 2104) | private static ComponentName selectProxyActivity(Intent intent) {
method selectProxyService (line 2119) | private static ServiceInfo selectProxyService(Intent intent) {
method selectProxyService (line 2133) | private static ComponentName selectProxyService(ComponentName componen...
method resolveActivity (line 2152) | private static ActivityInfo resolveActivity(Intent intent) throws Remo...
method resolveService (line 2156) | private static ServiceInfo resolveService(Intent intent) throws Remote...
method isPackagePlugin (line 2161) | private static boolean isPackagePlugin(String packageName) throws Remo...
method isComponentNamePlugin (line 2165) | private static boolean isComponentNamePlugin(ComponentName className) ...
method queryPluginApplicationInfo (line 2169) | private static ApplicationInfo queryPluginApplicationInfo(String packa...
method clearPluginApplicationUserData (line 2174) | private static boolean clearPluginApplicationUserData(String packageNa...
method tryfixServiceInfo (line 2183) | private static void tryfixServiceInfo(ActivityManager.RunningServiceIn...
class serviceDoneExecuting (line 2187) | private class serviceDoneExecuting extends ReplaceCallingPackageHooked...
method serviceDoneExecuting (line 2188) | public serviceDoneExecuting(Context context) {
method beforeInvoke (line 2192) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IAppOpsServiceHookHandle.java
class IAppOpsServiceHookHandle (line 33) | public class IAppOpsServiceHookHandle extends BaseHookHandle {
method IAppOpsServiceHookHandle (line 35) | public IAppOpsServiceHookHandle(Context hostContext) {
method init (line 39) | @Override
method getHookedClass (line 84) | @Override
method newBaseHandler (line 89) | @Override
class MyBaseHandler (line 94) | private static class MyBaseHandler extends ReplaceCallingPackageHooked...
method MyBaseHandler (line 95) | public MyBaseHandler(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IAudioServiceHookHandle.java
class IAudioServiceHookHandle (line 39) | public class IAudioServiceHookHandle extends BaseHookHandle {
method IAudioServiceHookHandle (line 41) | public IAudioServiceHookHandle(Context hostContext) {
method init (line 45) | @Override
class MyBaseHandler (line 59) | private static class MyBaseHandler extends HookedMethodHandler {
method MyBaseHandler (line 61) | public MyBaseHandler(Context context) {
method beforeInvoke (line 65) | @Override
class adjustVolume (line 84) | private static class adjustVolume extends MyBaseHandler {
method adjustVolume (line 85) | public adjustVolume(Context context) {
class adjustLocalOrRemoteStreamVolume (line 90) | private static class adjustLocalOrRemoteStreamVolume extends MyBaseHan...
method adjustLocalOrRemoteStreamVolume (line 91) | public adjustLocalOrRemoteStreamVolume(Context context) {
class adjustSuggestedStreamVolume (line 96) | private static class adjustSuggestedStreamVolume extends MyBaseHandler {
method adjustSuggestedStreamVolume (line 97) | public adjustSuggestedStreamVolume(Context context) {
class adjustStreamVolume (line 102) | private static class adjustStreamVolume extends MyBaseHandler {
method adjustStreamVolume (line 103) | public adjustStreamVolume(Context context) {
class adjustMasterVolume (line 108) | private static class adjustMasterVolume extends MyBaseHandler {
method adjustMasterVolume (line 109) | public adjustMasterVolume(Context context) {
class setStreamVolume (line 114) | private static class setStreamVolume extends MyBaseHandler {
method setStreamVolume (line 115) | public setStreamVolume(Context context) {
class setMasterVolume (line 120) | private static class setMasterVolume extends MyBaseHandler {
method setMasterVolume (line 121) | public setMasterVolume(Context context) {
class requestAudioFocus (line 126) | private static class requestAudioFocus extends MyBaseHandler {
method requestAudioFocus (line 127) | public requestAudioFocus(Context context) {
class registerRemoteControlClient (line 132) | private static class registerRemoteControlClient extends MyBaseHandler {
method registerRemoteControlClient (line 133) | public registerRemoteControlClient(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IClipboardHookHandle.java
class IClipboardHookHandle (line 35) | public class IClipboardHookHandle extends BaseHookHandle {
method IClipboardHookHandle (line 37) | public IClipboardHookHandle(Context context) {
method init (line 60) | @Override
class MyBaseHookedMethodHandler (line 71) | private class MyBaseHookedMethodHandler extends HookedMethodHandler {
method MyBaseHookedMethodHandler (line 72) | public MyBaseHookedMethodHandler(Context context) {
method beforeInvoke (line 76) | @Override
class setPrimaryClip (line 88) | private class setPrimaryClip extends MyBaseHookedMethodHandler {
method setPrimaryClip (line 89) | public setPrimaryClip(Context context) {
class getPrimaryClip (line 94) | private class getPrimaryClip extends MyBaseHookedMethodHandler {
method getPrimaryClip (line 95) | public getPrimaryClip(Context context) {
class getPrimaryClipDescription (line 100) | private class getPrimaryClipDescription extends MyBaseHookedMethodHand...
method getPrimaryClipDescription (line 101) | public getPrimaryClipDescription(Context context) {
class hasPrimaryClip (line 106) | private class hasPrimaryClip extends MyBaseHookedMethodHandler {
method hasPrimaryClip (line 107) | public hasPrimaryClip(Context context) {
class addPrimaryClipChangedListener (line 112) | private class addPrimaryClipChangedListener extends MyBaseHookedMethod...
method addPrimaryClipChangedListener (line 113) | public addPrimaryClipChangedListener(Context context) {
class removePrimaryClipChangedListener (line 118) | private class removePrimaryClipChangedListener extends MyBaseHookedMet...
method removePrimaryClipChangedListener (line 119) | public removePrimaryClipChangedListener(Context context) {
class hasClipboardText (line 124) | private class hasClipboardText extends MyBaseHookedMethodHandler {
method hasClipboardText (line 125) | public hasClipboardText(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IContentProviderInvokeHandle.java
class IContentProviderInvokeHandle (line 42) | public class IContentProviderInvokeHandle extends BaseHookHandle {
method IContentProviderInvokeHandle (line 47) | public IContentProviderInvokeHandle(Context hostContext, ProviderInfo ...
method init (line 55) | @Override
class MyHandler (line 74) | private class MyHandler extends ReplaceCallingPackageHookedMethodHandl...
method MyHandler (line 76) | public MyHandler(Context hostContext) {
method indexFirstUri (line 80) | private int indexFirstUri(Object[] args) {
method beforeInvoke (line 91) | @Override
class query (line 124) | private class query extends MyHandler {
method query (line 125) | public query(Context context) {
class getType (line 130) | private class getType extends MyHandler {
method getType (line 131) | public getType(Context context) {
class insert (line 136) | private class insert extends MyHandler {
method insert (line 137) | public insert(Context context) {
class bulkInsert (line 142) | private class bulkInsert extends MyHandler {
method bulkInsert (line 143) | public bulkInsert(Context context) {
class delete (line 148) | private class delete extends MyHandler {
method delete (line 149) | public delete(Context context) {
class update (line 154) | private class update extends MyHandler {
method update (line 155) | public update(Context context) {
class openFile (line 160) | private class openFile extends MyHandler {
method openFile (line 161) | public openFile(Context context) {
class openAssetFile (line 166) | private class openAssetFile extends MyHandler {
method openAssetFile (line 167) | public openAssetFile(Context context) {
class applyBatch (line 172) | private class applyBatch extends MyHandler {
method applyBatch (line 173) | public applyBatch(Context context) {
class call (line 178) | private class call extends MyHandler {
method call (line 179) | public call(Context context) {
class createCancellationSignal (line 184) | private class createCancellationSignal extends MyHandler {
method createCancellationSignal (line 185) | public createCancellationSignal(Context context) {
class canonicalize (line 190) | private class canonicalize extends MyHandler {
method canonicalize (line 191) | public canonicalize(Context context) {
class uncanonicalize (line 196) | private class uncanonicalize extends MyHandler {
method uncanonicalize (line 197) | public uncanonicalize(Context context) {
class getStreamTypes (line 202) | private class getStreamTypes extends MyHandler {
method getStreamTypes (line 203) | public getStreamTypes(Context context) {
class openTypedAssetFile (line 208) | private class openTypedAssetFile extends MyHandler {
method openTypedAssetFile (line 209) | public openTypedAssetFile(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IContentServiceHandle.java
class IContentServiceHandle (line 41) | public class IContentServiceHandle extends BaseHookHandle {
method IContentServiceHandle (line 45) | public IContentServiceHandle(Context hostContext) {
method init (line 49) | @Override
class IContentServiceHookedMethodHandler (line 55) | private static class IContentServiceHookedMethodHandler extends Hooked...
method IContentServiceHookedMethodHandler (line 58) | public IContentServiceHookedMethodHandler(Context hostContext) {
method beforeInvoke (line 62) | @Override
class registerContentObserver (line 89) | private static class registerContentObserver extends IContentServiceHo...
method registerContentObserver (line 90) | public registerContentObserver(Context hostContext) {
class notifyChange (line 95) | private static class notifyChange extends IContentServiceHookedMethodH...
method notifyChange (line 96) | public notifyChange(Context hostContext) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IDisplayManagerHookHandle.java
class IDisplayManagerHookHandle (line 17) | public class IDisplayManagerHookHandle extends BaseHookHandle {
method IDisplayManagerHookHandle (line 20) | public IDisplayManagerHookHandle(Context hostContext) {
method init (line 24) | @Override
class createVirtualDisplay (line 30) | private static class createVirtualDisplay extends HookedMethodHandler {
method createVirtualDisplay (line 33) | public createVirtualDisplay(Context hostContext) {
method beforeInvoke (line 37) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IGraphicsStatsHookHandle.java
class IGraphicsStatsHookHandle (line 36) | public class IGraphicsStatsHookHandle extends BaseHookHandle {
method IGraphicsStatsHookHandle (line 37) | public IGraphicsStatsHookHandle(Context hostContext) {
method init (line 41) | @Override
class requestBufferForProcess (line 46) | private class requestBufferForProcess extends HookedMethodHandler {
method requestBufferForProcess (line 47) | public requestBufferForProcess(Context hostContext) {
method beforeInvoke (line 51) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IInputMethodManagerHookHandle.java
class IInputMethodManagerHookHandle (line 37) | public class IInputMethodManagerHookHandle extends BaseHookHandle {
method IInputMethodManagerHookHandle (line 39) | public IInputMethodManagerHookHandle(Context hostContext) {
method init (line 43) | @Override
class IInputMethodManagerHookedMethodHandler (line 50) | private class IInputMethodManagerHookedMethodHandler extends HookedMet...
method IInputMethodManagerHookedMethodHandler (line 51) | public IInputMethodManagerHookedMethodHandler(Context hostContext) {
method beforeInvoke (line 55) | @Override
class startInput (line 71) | private class startInput extends IInputMethodManagerHookedMethodHandler {
method startInput (line 72) | public startInput(Context hostContext) {
class windowGainedFocus (line 77) | private class windowGainedFocus extends IInputMethodManagerHookedMetho...
method windowGainedFocus (line 78) | public windowGainedFocus(Context hostContext) {
class startInputOrWindowGainedFocus (line 83) | private class startInputOrWindowGainedFocus extends IInputMethodManage...
method startInputOrWindowGainedFocus (line 84) | public startInputOrWindowGainedFocus(Context hostContext) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ILocationManagerHookHandle.java
class ILocationManagerHookHandle (line 33) | public class ILocationManagerHookHandle extends BaseHookHandle {
method ILocationManagerHookHandle (line 36) | public ILocationManagerHookHandle(Context hostContext) {
method init (line 40) | @Override
class BaseILocationManagerHookedMethodHandler (line 52) | private static class BaseILocationManagerHookedMethodHandler extends R...
method BaseILocationManagerHookedMethodHandler (line 53) | public BaseILocationManagerHookedMethodHandler(Context hostContext) {
class requestLocationUpdates (line 58) | private class requestLocationUpdates extends BaseILocationManagerHooke...
method requestLocationUpdates (line 59) | public requestLocationUpdates(Context hostContext) {
class removeUpdates (line 64) | private class removeUpdates extends BaseILocationManagerHookedMethodHa...
method removeUpdates (line 65) | public removeUpdates(Context hostContext) {
class requestGeofence (line 70) | private class requestGeofence extends BaseILocationManagerHookedMethod...
method requestGeofence (line 71) | public requestGeofence(Context hostContext) {
class removeGeofence (line 76) | private class removeGeofence extends BaseILocationManagerHookedMethodH...
method removeGeofence (line 77) | public removeGeofence(Context hostContext) {
class getLastLocation (line 82) | private class getLastLocation extends BaseILocationManagerHookedMethod...
method getLastLocation (line 83) | public getLastLocation(Context hostContext) {
class addGpsStatusListener (line 88) | private class addGpsStatusListener extends BaseILocationManagerHookedM...
method addGpsStatusListener (line 89) | public addGpsStatusListener(Context hostContext) {
class removeGpsStatusListener (line 94) | private class removeGpsStatusListener extends BaseILocationManagerHook...
method removeGpsStatusListener (line 95) | public removeGpsStatusListener(Context hostContext) {
class geocoderIsPresent (line 100) | private class geocoderIsPresent extends BaseILocationManagerHookedMeth...
method geocoderIsPresent (line 101) | public geocoderIsPresent(Context hostContext) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IMediaRouterServiceHookHandle.java
class IMediaRouterServiceHookHandle (line 35) | public class IMediaRouterServiceHookHandle extends BaseHookHandle {
method IMediaRouterServiceHookHandle (line 37) | public IMediaRouterServiceHookHandle(Context hostContext) {
method init (line 41) | @Override
class registerClientAsUser (line 54) | private class registerClientAsUser extends HookedMethodHandler {
method registerClientAsUser (line 55) | public registerClientAsUser(Context context) {
method beforeInvoke (line 59) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IMmsHookHandle.java
class IMmsHookHandle (line 33) | public class IMmsHookHandle extends BaseHookHandle {
method IMmsHookHandle (line 35) | public IMmsHookHandle(Context hostContext) {
method init (line 39) | @Override
method getHookedClass (line 86) | @Override
method newBaseHandler (line 91) | @Override
class MyBaseHandler (line 96) | private static class MyBaseHandler extends ReplaceCallingPackageHooked...
method MyBaseHandler (line 97) | public MyBaseHandler(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IMountServiceHookHandle.java
class IMountServiceHookHandle (line 40) | public class IMountServiceHookHandle extends BaseHookHandle {
method IMountServiceHookHandle (line 45) | public IMountServiceHookHandle(Context context) {
method init (line 49) | @Override
class mkdirs (line 55) | private class mkdirs extends HookedMethodHandler {
method mkdirs (line 56) | public mkdirs(Context context) {
method beforeInvoke (line 63) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/INotificationManagerHookHandle.java
class INotificationManagerHookHandle (line 61) | public class INotificationManagerHookHandle extends BaseHookHandle {
method INotificationManagerHookHandle (line 65) | public INotificationManagerHookHandle(Context context) {
method init (line 69) | @Override
method init1 (line 118) | private static void init1() {
method getResIdByName (line 139) | public static int getResIdByName(String name) {
class MyNotification (line 148) | private class MyNotification extends HookedMethodHandler {
method MyNotification (line 149) | public MyNotification(Context context) {
method beforeInvoke (line 153) | @Override
method findFisrtNotificationIndex (line 168) | private int findFisrtNotificationIndex(Object[] args) {
class enqueueNotification (line 179) | private class enqueueNotification extends MyNotification {
method enqueueNotification (line 180) | public enqueueNotification(Context context) {
method beforeInvoke (line 186) | @Override
method hackRemoteViews (line 214) | private void hackRemoteViews(RemoteViews remoteViews) throws IllegalAc...
method shouldBlockByRemoteViews (line 270) | private boolean shouldBlockByRemoteViews(RemoteViews remoteViews) {
method shouldBlock (line 280) | private boolean shouldBlock(Notification notification) {
method isPluginNotification (line 302) | private boolean isPluginNotification(Notification notification) {
method drawableToBitMap (line 377) | private Bitmap drawableToBitMap(Drawable drawable) {
method hackNotification (line 391) | private void hackNotification(Notification notification) throws Illega...
class cancelNotification (line 446) | private class cancelNotification extends MyNotification {
method cancelNotification (line 447) | public cancelNotification(Context context) {
class cancelAllNotifications (line 455) | private class cancelAllNotifications extends MyNotification {
method cancelAllNotifications (line 456) | public cancelAllNotifications(Context context) {
class enqueueToast (line 463) | private class enqueueToast extends MyNotification {
method enqueueToast (line 464) | public enqueueToast(Context context) {
method beforeInvoke (line 470) | @Override
class cancelToast (line 491) | private class cancelToast extends MyNotification {
method cancelToast (line 492) | public cancelToast(Context context) {
method beforeInvoke (line 498) | @Override
class enqueueNotificationWithTag (line 516) | private class enqueueNotificationWithTag extends MyNotification {
method enqueueNotificationWithTag (line 517) | public enqueueNotificationWithTag(Context context) {
method beforeInvoke (line 523) | @Override
class enqueueNotificationWithTagPriority (line 550) | private class enqueueNotificationWithTagPriority extends MyNotification {
method enqueueNotificationWithTagPriority (line 551) | public enqueueNotificationWithTagPriority(Context context) {
method beforeInvoke (line 557) | @Override
class cancelNotificationWithTag (line 585) | private class cancelNotificationWithTag extends MyNotification {
method cancelNotificationWithTag (line 586) | public cancelNotificationWithTag(Context context) {
class setNotificationsEnabledForPackage (line 593) | private class setNotificationsEnabledForPackage extends MyNotification {
method setNotificationsEnabledForPackage (line 594) | public setNotificationsEnabledForPackage(Context context) {
class areNotificationsEnabledForPackage (line 599) | private class areNotificationsEnabledForPackage extends MyNotification {
method areNotificationsEnabledForPackage (line 600) | public areNotificationsEnabledForPackage(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IPackageManagerHookHandle.java
class IPackageManagerHookHandle (line 59) | public class IPackageManagerHookHandle extends BaseHookHandle {
method IPackageManagerHookHandle (line 63) | public IPackageManagerHookHandle(Context hostContext) {
method init (line 67) | @Override
class getPackageInfo (line 134) | private class getPackageInfo extends HookedMethodHandler {
method getPackageInfo (line 135) | public getPackageInfo(Context context) {
method beforeInvoke (line 139) | @Override
class getPackageUid (line 182) | private class getPackageUid extends HookedMethodHandler {
method getPackageUid (line 183) | public getPackageUid(Context context) {
method beforeInvoke (line 187) | @Override
class getPackageGids (line 210) | private class getPackageGids extends HookedMethodHandler {
method getPackageGids (line 211) | public getPackageGids(Context context) {
method beforeInvoke (line 215) | @Override
class currentToCanonicalPackageNames (line 236) | private class currentToCanonicalPackageNames extends HookedMethodHandl...
method currentToCanonicalPackageNames (line 237) | public currentToCanonicalPackageNames(Context context) {
class canonicalToCurrentPackageNames (line 244) | private class canonicalToCurrentPackageNames extends HookedMethodHandl...
method canonicalToCurrentPackageNames (line 245) | public canonicalToCurrentPackageNames(Context context) {
class getPermissionInfo (line 253) | private class getPermissionInfo extends HookedMethodHandler {
method getPermissionInfo (line 254) | public getPermissionInfo(Context context) {
method beforeInvoke (line 258) | @Override
class queryPermissionsByGroup (line 279) | private class queryPermissionsByGroup extends HookedMethodHandler {
method queryPermissionsByGroup (line 280) | public queryPermissionsByGroup(Context context) {
method afterInvoke (line 284) | @Override
class getPermissionGroupInfo (line 304) | private class getPermissionGroupInfo extends HookedMethodHandler {
method getPermissionGroupInfo (line 305) | public getPermissionGroupInfo(Context context) {
method beforeInvoke (line 309) | @Override
class getAllPermissionGroups (line 329) | private class getAllPermissionGroups extends HookedMethodHandler {
method getAllPermissionGroups (line 330) | public getAllPermissionGroups(Context context) {
method afterInvoke (line 334) | @Override
class getApplicationInfo (line 353) | private class getApplicationInfo extends HookedMethodHandler {
method getApplicationInfo (line 354) | public getApplicationInfo(Context context) {
method beforeInvoke (line 358) | @Override
class getActivityInfo (line 380) | private class getActivityInfo extends HookedMethodHandler {
method getActivityInfo (line 381) | public getActivityInfo(Context context) {
method beforeInvoke (line 385) | @Override
class getReceiverInfo (line 407) | private class getReceiverInfo extends HookedMethodHandler {
method getReceiverInfo (line 408) | public getReceiverInfo(Context context) {
method beforeInvoke (line 412) | @Override
class getServiceInfo (line 434) | private class getServiceInfo extends HookedMethodHandler {
method getServiceInfo (line 435) | public getServiceInfo(Context context) {
method beforeInvoke (line 439) | @Override
class getProviderInfo (line 461) | private class getProviderInfo extends HookedMethodHandler {
method getProviderInfo (line 462) | public getProviderInfo(Context context) {
method beforeInvoke (line 466) | @Override
class checkPermission (line 488) | private class checkPermission extends HookedMethodHandler {
method checkPermission (line 489) | public checkPermission(Context context) {
method beforeInvoke (line 493) | @Override
class checkUidPermission (line 510) | private class checkUidPermission extends HookedMethodHandler {
method checkUidPermission (line 511) | public checkUidPermission(Context context) {
class addPermission (line 518) | private class addPermission extends HookedMethodHandler {
method addPermission (line 519) | public addPermission(Context context) {
class removePermission (line 527) | private class removePermission extends HookedMethodHandler {
method removePermission (line 528) | public removePermission(Context context) {
class grantPermission (line 536) | private class grantPermission extends HookedMethodHandler {
method grantPermission (line 537) | public grantPermission(Context context) {
method beforeInvoke (line 541) | @Override
class revokePermission (line 560) | private class revokePermission extends HookedMethodHandler {
method revokePermission (line 561) | public revokePermission(Context context) {
method beforeInvoke (line 565) | @Override
class checkSignatures (line 584) | private class checkSignatures extends HookedMethodHandler {
method checkSignatures (line 585) | public checkSignatures(Context context) {
method beforeInvoke (line 589) | @Override
class getPackagesForUid (line 615) | private class getPackagesForUid extends HookedMethodHandler {
method getPackagesForUid (line 616) | public getPackagesForUid(Context context) {
class getNameForUid (line 623) | private class getNameForUid extends HookedMethodHandler {
method getNameForUid (line 624) | public getNameForUid(Context context) {
class getUidForSharedUser (line 631) | private class getUidForSharedUser extends HookedMethodHandler {
method getUidForSharedUser (line 632) | public getUidForSharedUser(Context context) {
class getFlagsForUid (line 639) | private class getFlagsForUid extends HookedMethodHandler {
method getFlagsForUid (line 640) | public getFlagsForUid(Context context) {
class resolveIntent (line 649) | private class resolveIntent extends HookedMethodHandler {
method resolveIntent (line 650) | public resolveIntent(Context context) {
method beforeInvoke (line 654) | @Override
class queryIntentActivities (line 696) | private class queryIntentActivities extends HookedMethodHandler {
method queryIntentActivities (line 697) | public queryIntentActivities(Context context) {
method afterInvoke (line 701) | @Override
class queryIntentActivityOptions (line 748) | private class queryIntentActivityOptions extends HookedMethodHandler {
method queryIntentActivityOptions (line 749) | public queryIntentActivityOptions(Context context) {
class queryIntentReceivers (line 759) | private class queryIntentReceivers extends HookedMethodHandler {
method queryIntentReceivers (line 760) | public queryIntentReceivers(Context context) {
method afterInvoke (line 764) | @Override
class resolveService (line 811) | private class resolveService extends HookedMethodHandler {
method resolveService (line 812) | public resolveService(Context context) {
method beforeInvoke (line 816) | @Override
class queryIntentServices (line 857) | private class queryIntentServices extends HookedMethodHandler {
method queryIntentServices (line 858) | public queryIntentServices(Context context) {
method afterInvoke (line 862) | @Override
class queryIntentContentProviders (line 909) | private class queryIntentContentProviders extends HookedMethodHandler {
method queryIntentContentProviders (line 910) | public queryIntentContentProviders(Context context) {
method afterInvoke (line 914) | @Override
class getInstalledPackages (line 961) | private class getInstalledPackages extends HookedMethodHandler {
method getInstalledPackages (line 962) | public getInstalledPackages(Context context) {
method afterInvoke (line 966) | @Override
class getPackagesHoldingPermissions (line 1047) | private class getPackagesHoldingPermissions extends HookedMethodHandler {
method getPackagesHoldingPermissions (line 1048) | public getPackagesHoldingPermissions(Context context) {
class getInstalledApplications (line 1057) | private class getInstalledApplications extends HookedMethodHandler {
method getInstalledApplications (line 1058) | public getInstalledApplications(Context context) {
method afterInvoke (line 1062) | @Override
class getPersistentApplications (line 1142) | private class getPersistentApplications extends HookedMethodHandler {
method getPersistentApplications (line 1143) | public getPersistentApplications(Context context) {
class resolveContentProvider (line 1150) | private class resolveContentProvider extends HookedMethodHandler {
method resolveContentProvider (line 1151) | public resolveContentProvider(Context context) {
method beforeInvoke (line 1155) | @Override
method afterInvoke (line 1165) | @Override
class querySyncProviders (line 1184) | private class querySyncProviders extends HookedMethodHandler {
method querySyncProviders (line 1185) | public querySyncProviders(Context context) {
class queryContentProviders (line 1193) | private class queryContentProviders extends HookedMethodHandler {
method queryContentProviders (line 1194) | public queryContentProviders(Context context) {
class getInstrumentationInfo (line 1203) | private class getInstrumentationInfo extends HookedMethodHandler {
method getInstrumentationInfo (line 1204) | public getInstrumentationInfo(Context context) {
class queryInstrumentation (line 1213) | private class queryInstrumentation extends HookedMethodHandler {
method queryInstrumentation (line 1214) | public queryInstrumentation(Context context) {
class getInstallerPackageName (line 1223) | private class getInstallerPackageName extends HookedMethodHandler {
method getInstallerPackageName (line 1224) | public getInstallerPackageName(Context context) {
method beforeInvoke (line 1228) | @Override
class addPackageToPreferred (line 1246) | private class addPackageToPreferred extends HookedMethodHandler {
method addPackageToPreferred (line 1247) | public addPackageToPreferred(Context context) {
method beforeInvoke (line 1251) | @Override
class removePackageFromPreferred (line 1268) | private class removePackageFromPreferred extends HookedMethodHandler {
method removePackageFromPreferred (line 1269) | public removePackageFromPreferred(Context context) {
method beforeInvoke (line 1273) | @Override
class getPreferredPackages (line 1290) | private class getPreferredPackages extends HookedMethodHandler {
method getPreferredPackages (line 1291) | public getPreferredPackages(Context context) {
class resetPreferredActivities (line 1299) | private class resetPreferredActivities extends HookedMethodHandler {
method resetPreferredActivities (line 1300) | public resetPreferredActivities(Context context) {
class getLastChosenActivity (line 1308) | private class getLastChosenActivity extends HookedMethodHandler {
method getLastChosenActivity (line 1309) | public getLastChosenActivity(Context context) {
class setLastChosenActivity (line 1317) | private class setLastChosenActivity extends HookedMethodHandler {
method setLastChosenActivity (line 1318) | public setLastChosenActivity(Context context) {
class addPreferredActivity (line 1327) | private class addPreferredActivity extends HookedMethodHandler {
method addPreferredActivity (line 1328) | public addPreferredActivity(Context context) {
class replacePreferredActivity (line 1339) | private class replacePreferredActivity extends HookedMethodHandler {
method replacePreferredActivity (line 1340) | public replacePreferredActivity(Context context) {
class clearPackagePreferredActivities (line 1352) | private class clearPackagePreferredActivities extends HookedMethodHand...
method clearPackagePreferredActivities (line 1353) | public clearPackagePreferredActivities(Context context) {
method beforeInvoke (line 1357) | @Override
class getPreferredActivities (line 1374) | private class getPreferredActivities extends HookedMethodHandler {
method getPreferredActivities (line 1375) | public getPreferredActivities(Context context) {
class getHomeActivities (line 1385) | private class getHomeActivities extends HookedMethodHandler {
method getHomeActivities (line 1386) | public getHomeActivities(Context context) {
class setComponentEnabledSetting (line 1395) | private class setComponentEnabledSetting extends HookedMethodHandler {
method setComponentEnabledSetting (line 1396) | public setComponentEnabledSetting(Context context) {
method beforeInvoke (line 1416) | @Override
class getComponentEnabledSetting (line 1430) | private class getComponentEnabledSetting extends HookedMethodHandler {
method getComponentEnabledSetting (line 1431) | public getComponentEnabledSetting(Context context) {
method beforeInvoke (line 1440) | @Override
class setApplicationEnabledSetting (line 1454) | private class setApplicationEnabledSetting extends HookedMethodHandler {
method setApplicationEnabledSetting (line 1455) | public setApplicationEnabledSetting(Context context) {
method beforeInvoke (line 1465) | @Override
class getApplicationEnabledSetting (line 1478) | private class getApplicationEnabledSetting extends HookedMethodHandler {
method getApplicationEnabledSetting (line 1479) | public getApplicationEnabledSetting(Context context) {
method beforeInvoke (line 1483) | @Override
class setPackageStoppedState (line 1504) | private class setPackageStoppedState extends HookedMethodHandler {
method setPackageStoppedState (line 1505) | public setPackageStoppedState(Context context) {
method beforeInvoke (line 1509) | @Override
class deleteApplicationCacheFiles (line 1531) | private class deleteApplicationCacheFiles extends HookedMethodHandler {
method deleteApplicationCacheFiles (line 1532) | public deleteApplicationCacheFiles(Context context) {
method beforeInvoke (line 1536) | @Override
class clearApplicationUserData (line 1555) | private class clearApplicationUserData extends HookedMethodHandler {
method clearApplicationUserData (line 1556) | public clearApplicationUserData(Context context) {
method beforeInvoke (line 1560) | @Override
class getPackageSizeInfo (line 1581) | private class getPackageSizeInfo extends HookedMethodHandler {
method getPackageSizeInfo (line 1582) | public getPackageSizeInfo(Context context) {
method beforeInvoke (line 1586) | @Override
class performDexOpt (line 1597) | private class performDexOpt extends HookedMethodHandler {
method performDexOpt (line 1598) | public performDexOpt(Context context) {
class movePackage (line 1607) | private class movePackage extends HookedMethodHandler {
method movePackage (line 1608) | public movePackage(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IPhoneSubInfoHookHandle.java
class IPhoneSubInfoHookHandle (line 33) | public class IPhoneSubInfoHookHandle extends BaseHookHandle {
method IPhoneSubInfoHookHandle (line 35) | public IPhoneSubInfoHookHandle(Context hostContext) {
method init (line 39) | @Override
method getHookedClass (line 226) | @Override
method newBaseHandler (line 231) | @Override
class MyBaseHandler (line 236) | private static class MyBaseHandler extends ReplaceCallingPackageHooked...
method MyBaseHandler (line 237) | public MyBaseHandler(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ISearchManagerHookHandle.java
class ISearchManagerHookHandle (line 39) | public class ISearchManagerHookHandle extends BaseHookHandle {
method ISearchManagerHookHandle (line 41) | public ISearchManagerHookHandle(Context context) {
method init (line 44) | @Override
class getSearchableInfo (line 50) | private class getSearchableInfo extends HookedMethodHandler{
method getSearchableInfo (line 52) | public getSearchableInfo(Context hostContext) {
method beforeInvoke (line 56) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ISessionManagerHookHandle.java
class ISessionManagerHookHandle (line 35) | public class ISessionManagerHookHandle extends BaseHookHandle {
method ISessionManagerHookHandle (line 37) | public ISessionManagerHookHandle(Context context) {
method init (line 41) | @Override
class createSession (line 46) | private class createSession extends HookedMethodHandler {
method createSession (line 47) | public createSession(Context context) {
method beforeInvoke (line 51) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ISmsHookHandle.java
class ISmsHookHandle (line 33) | public class ISmsHookHandle extends BaseHookHandle{
method ISmsHookHandle (line 37) | public ISmsHookHandle(Context hostContext) {
method init (line 41) | @Override
method getHookedClass (line 117) | @Override
method newBaseHandler (line 122) | @Override
class MyBaseHandler (line 127) | private static class MyBaseHandler extends ReplaceCallingPackageHooked...
method MyBaseHandler (line 128) | public MyBaseHandler(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ISubBinderHookHandle.java
class ISubBinderHookHandle (line 33) | public class ISubBinderHookHandle extends BaseHookHandle {
method ISubBinderHookHandle (line 35) | public ISubBinderHookHandle(Context hostContext) {
method init (line 39) | @Override
method getHookedClass (line 212) | @Override
method newBaseHandler (line 217) | @Override
class MyBaseHandler (line 222) | private static class MyBaseHandler extends ReplaceCallingPackageHooked...
method MyBaseHandler (line 223) | public MyBaseHandler(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ITelephonyHookHandle.java
class ITelephonyHookHandle (line 33) | public class ITelephonyHookHandle extends BaseHookHandle {
method ITelephonyHookHandle (line 34) | public ITelephonyHookHandle(Context hostContext) {
method init (line 38) | @Override
method getHookedClass (line 1018) | @Override
method newBaseHandler (line 1023) | @Override
class MyBaseHandler (line 1028) | private static class MyBaseHandler extends ReplaceCallingPackageHooked...
method MyBaseHandler (line 1029) | public MyBaseHandler(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ITelephonyRegistryHookHandle.java
class ITelephonyRegistryHookHandle (line 33) | public class ITelephonyRegistryHookHandle extends BaseHookHandle {
method ITelephonyRegistryHookHandle (line 35) | public ITelephonyRegistryHookHandle(Context hostContext) {
method init (line 39) | @Override
method getHookedClass (line 111) | @Override
method newBaseHandler (line 116) | @Override
class MyBaseHandler (line 120) | private static class MyBaseHandler extends ReplaceCallingPackageHooked...
method MyBaseHandler (line 121) | public MyBaseHandler(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IWifiManagerHookHandle.java
class IWifiManagerHookHandle (line 37) | public class IWifiManagerHookHandle extends BaseHookHandle {
method IWifiManagerHookHandle (line 39) | public IWifiManagerHookHandle(Context hostContext) {
method init (line 43) | @Override
class IWifiManagerHookedMethodHandler (line 50) | private class IWifiManagerHookedMethodHandler extends HookedMethodHand...
method IWifiManagerHookedMethodHandler (line 51) | public IWifiManagerHookedMethodHandler(Context hostContext) {
method beforeInvoke (line 55) | @Override
class getScanResults (line 69) | private class getScanResults extends IWifiManagerHookedMethodHandler {
method getScanResults (line 70) | public getScanResults(Context hostContext) {
class getBatchedScanResults (line 75) | private class getBatchedScanResults extends IWifiManagerHookedMethodHa...
method getBatchedScanResults (line 76) | public getBatchedScanResults(Context hostContext) {
class setWifiEnabled (line 81) | private class setWifiEnabled extends HookedMethodHandler {
method setWifiEnabled (line 82) | public setWifiEnabled(Context hostContext) {
method beforeInvoke (line 160) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IWindowManagerHookHandle.java
class IWindowManagerHookHandle (line 41) | public class IWindowManagerHookHandle extends BaseHookHandle {
method IWindowManagerHookHandle (line 43) | public IWindowManagerHookHandle(Context hostContext) {
method init (line 47) | @Override
class openSession (line 55) | private class openSession extends HookedMethodHandler {
method openSession (line 56) | public openSession(Context hostContext) {
method afterInvoke (line 60) | @Override
class overridePendingAppTransition (line 73) | private class overridePendingAppTransition extends HookedMethodHandler {
method overridePendingAppTransition (line 74) | public overridePendingAppTransition(Context hostContext) {
class setAppStartingWindow (line 79) | private class setAppStartingWindow extends HookedMethodHandler {
method setAppStartingWindow (line 80) | public setAppStartingWindow(Context hostContext) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IWindowSessionInvokeHandle.java
class IWindowSessionInvokeHandle (line 38) | public class IWindowSessionInvokeHandle extends BaseHookHandle {
method IWindowSessionInvokeHandle (line 40) | public IWindowSessionInvokeHandle(Context hostContext) {
method init (line 44) | @Override
class IWindowSessionHookedMethodHandler (line 53) | private class IWindowSessionHookedMethodHandler extends HookedMethodHa...
method IWindowSessionHookedMethodHandler (line 54) | public IWindowSessionHookedMethodHandler(Context hostContext) {
method findWindowManagerLayoutParamsIndex (line 58) | int findWindowManagerLayoutParamsIndex(Object[] args) {
method beforeInvoke (line 71) | @Override
class add (line 94) | private class add extends IWindowSessionHookedMethodHandler {
method add (line 95) | public add(Context hostContext) {
class addToDisplay (line 100) | private class addToDisplay extends IWindowSessionHookedMethodHandler {
method addToDisplay (line 101) | public addToDisplay(Context hostContext) {
class addWithoutInputChannel (line 106) | private class addWithoutInputChannel extends IWindowSessionHookedMetho...
method addWithoutInputChannel (line 107) | public addWithoutInputChannel(Context hostContext) {
class addToDisplayWithoutInputChannel (line 112) | private class addToDisplayWithoutInputChannel extends IWindowSessionHo...
method addToDisplayWithoutInputChannel (line 113) | public addToDisplayWithoutInputChannel(Context hostContext) {
class relayout (line 118) | private class relayout extends IWindowSessionHookedMethodHandler {
method relayout (line 119) | public relayout(Context hostContext) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/LibCoreHookHandle.java
class LibCoreHookHandle (line 40) | public class LibCoreHookHandle extends BaseHookHandle {
method LibCoreHookHandle (line 42) | public LibCoreHookHandle(Context hostContext) {
method init (line 48) | @Override
class BaseLibCore (line 64) | private abstract static class BaseLibCore extends HookedMethodHandler {
method BaseLibCore (line 70) | public BaseLibCore(Context context) {
method beforeInvoke (line 78) | @Override
method replace (line 88) | protected void replace(Object[] args, int index) {
method tryReplacePath (line 99) | private String tryReplacePath(String tarDir) {
class access (line 122) | private class access extends BaseLibCore {
method access (line 123) | public access(Context context) {
class chmod (line 128) | private class chmod extends BaseLibCore {
method chmod (line 129) | public chmod(Context context) {
class chown (line 134) | private class chown extends BaseLibCore {
method chown (line 135) | public chown(Context context) {
class execv (line 140) | private class execv extends BaseLibCore {
method execv (line 141) | public execv(Context context) {
class execve (line 146) | private class execve extends BaseLibCore {
method execve (line 147) | public execve(Context context) {
class mkdir (line 152) | private class mkdir extends BaseLibCore {
method mkdir (line 153) | public mkdir(Context context) {
class open (line 158) | private class open extends BaseLibCore {
method open (line 159) | public open(Context context) {
class remove (line 164) | private class remove extends BaseLibCore {
method remove (line 165) | public remove(Context context) {
class rename (line 170) | private class rename extends BaseLibCore {
method rename (line 171) | public rename(Context context) {
method beforeInvoke (line 175) | @Override
class stat (line 183) | private class stat extends BaseLibCore {
method stat (line 184) | public stat(Context context) {
class statvfs (line 189) | private class statvfs extends BaseLibCore {
method statvfs (line 190) | public statvfs(Context context) {
class symlink (line 195) | private class symlink extends BaseLibCore {
method symlink (line 196) | public symlink(Context context) {
method beforeInvoke (line 200) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/PluginCallback.java
class PluginCallback (line 45) | public class PluginCallback implements Handler.Callback {
method codeToString (line 100) | String codeToString(int code) {
method PluginCallback (line 211) | public PluginCallback(Context hostContext, Handler oldHandle, Handler....
method setEnable (line 217) | public void setEnable(boolean enable) {
method isEnable (line 221) | public boolean isEnable() {
method handleMessage (line 225) | @Override
method handleLaunchActivity (line 352) | private boolean handleLaunchActivity(Message msg) {
method isShortcutProxyActivity (line 440) | private boolean isShortcutProxyActivity(Intent targetIntent) {
method fixedClassLoader (line 460) | private ClassLoader fixedClassLoader(ClassLoader newParent) {
method setIntentClassLoader (line 473) | private void setIntentClassLoader(Intent intent, ClassLoader classLoad...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/PluginInstrumentation.java
class PluginInstrumentation (line 57) | public class PluginInstrumentation extends Instrumentation {
method setEnable (line 65) | public void setEnable(boolean enable) {
method PluginInstrumentation (line 71) | public PluginInstrumentation(Context hostContext, Instrumentation targ...
method callActivityOnCreate (line 77) | @Override
method fixBaseContextImplOpsPackage (line 116) | private void fixBaseContextImplOpsPackage(Context context) throws Ille...
method fixBaseContextImplContentResolverOpsPackage (line 134) | private void fixBaseContextImplContentResolverOpsPackage(Context conte...
method onActivityCreated (line 159) | private void onActivityCreated(Activity activity) throws RemoteExcepti...
method onActivityOnNewIntent (line 182) | private void onActivityOnNewIntent(Activity activity, Intent intent) t...
method fixTaskDescription (line 199) | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
method onActivityDestory (line 221) | private void onActivityDestory(Activity activity) throws RemoteExcepti...
method callActivityOnDestroy (line 232) | @Override
method callApplicationOnCreate (line 250) | @Override
method callActivityOnNewIntent (line 294) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ReplaceCallingPackageHookedMethodHandler.java
class ReplaceCallingPackageHookedMethodHandler (line 12) | class ReplaceCallingPackageHookedMethodHandler extends HookedMethodHandl...
method ReplaceCallingPackageHookedMethodHandler (line 14) | public ReplaceCallingPackageHookedMethodHandler(Context hostContext) {
method beforeInvoke (line 18) | @Override
method isPackagePlugin (line 35) | private static boolean isPackagePlugin(String packageName) throws Remo...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/WebViewFactoryProviderHookHandle.java
class WebViewFactoryProviderHookHandle (line 43) | public class WebViewFactoryProviderHookHandle extends BaseHookHandle {
method WebViewFactoryProviderHookHandle (line 47) | public WebViewFactoryProviderHookHandle(Context hostContext) {
method init (line 51) | @Override
method fixWebViewAsset (line 58) | private static void fixWebViewAsset(Context context) {
class createWebView (line 90) | private static class createWebView extends HookedMethodHandler {
method beforeInvoke (line 94) | @Override
method createWebView (line 103) | public createWebView(Context context) {
method afterInvoke (line 108) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/IActivityManagerHook.java
class IActivityManagerHook (line 49) | public class IActivityManagerHook extends ProxyHook {
method IActivityManagerHook (line 53) | public IActivityManagerHook(Context hostContext) {
method createHookHandle (line 57) | @Override
method invoke (line 62) | @Override
method onInstall (line 74) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/IContentProviderHook.java
class IContentProviderHook (line 34) | public class IContentProviderHook extends ProxyHook {
method IContentProviderHook (line 42) | public IContentProviderHook(Context context, Object oldObj, ProviderIn...
method createHookHandle (line 52) | @Override
method onInstall (line 57) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/IPackageManagerHook.java
class IPackageManagerHook (line 50) | public class IPackageManagerHook extends ProxyHook {
method IPackageManagerHook (line 54) | public IPackageManagerHook(Context hostContext) {
method createHookHandle (line 58) | @Override
method onInstall (line 63) | @Override
method fixContextPackageManager (line 81) | public static void fixContextPackageManager(Context context) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/IWindowSessionHook.java
class IWindowSessionHook (line 35) | public class IWindowSessionHook extends ProxyHook {
method IWindowSessionHook (line 39) | public IWindowSessionHook(Context context, Object oldObj) {
method createHookHandle (line 46) | @Override
method onInstall (line 51) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/InstrumentationHook.java
class InstrumentationHook (line 43) | public class InstrumentationHook extends Hook {
method InstrumentationHook (line 48) | public InstrumentationHook(Context hostContext) {
method createHookHandle (line 52) | @Override
method setEnable (line 57) | @Override
method onInstall (line 74) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/LibCoreHook.java
class LibCoreHook (line 38) | public class LibCoreHook extends ProxyHook {
method LibCoreHook (line 42) | public LibCoreHook(Context hostContext) throws ClassNotFoundException {
method createHookHandle (line 46) | @Override
method getAllInterfaces (line 51) | private Class<?>[] getAllInterfaces(Class clz) {
method onInstall (line 73) | @Override
method installHook1 (line 80) | private boolean installHook1() {
method installHook2 (line 97) | private void installHook2() throws ClassNotFoundException, IllegalAcce...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/PluginCallbackHook.java
class PluginCallbackHook (line 42) | public class PluginCallbackHook extends Hook {
method PluginCallbackHook (line 47) | public PluginCallbackHook(Context hostContext) {
method createHookHandle (line 51) | @Override
method setEnable (line 56) | @Override
method onInstall (line 72) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/ProxyHook.java
class ProxyHook (line 40) | public abstract class ProxyHook extends Hook implements InvocationHandler {
method ProxyHook (line 44) | public ProxyHook(Context hostContext) {
method setOldObj (line 48) | public void setOldObj(Object oldObj) {
method invoke (line 52) | public Object invoke(Object proxy, Method method, Object[] args) throw...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/WebViewFactoryProviderHook.java
class WebViewFactoryProviderHook (line 45) | public class WebViewFactoryProviderHook extends ProxyHook {
method WebViewFactoryProviderHook (line 47) | public WebViewFactoryProviderHook(Context hostContext) {
method createHookHandle (line 51) | @Override
method onInstall (line 56) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/xhook/SQLiteDatabaseHook.java
class SQLiteDatabaseHook (line 38) | public class SQLiteDatabaseHook extends Hook {
method SQLiteDatabaseHook (line 47) | public SQLiteDatabaseHook(Context hostContext) {
method createHookHandle (line 54) | @Override
method tryReplacePath (line 60) | private String tryReplacePath(String tarDir) {
method replace (line 82) | protected void replace(Object[] args, int index) {
method onInstall (line 92) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/IPluginManagerImpl.java
class IPluginManagerImpl (line 75) | public class IPluginManagerImpl extends IPluginManager.Stub {
method IPluginManagerImpl (line 92) | public IPluginManagerImpl(Context context) {
method onCreate (line 97) | public void onCreate() {
method onCreateInner (line 106) | private void onCreateInner() {
method loadHostRequestedPermission (line 118) | private void loadHostRequestedPermission() {
method loadAllPlugin (line 133) | private void loadAllPlugin(Context context) {
method enforcePluginFileExists (line 192) | private void enforcePluginFileExists() throws RemoteException {
method waitForReady (line 209) | @Override
method waitForReadyInner (line 215) | private void waitForReadyInner() {
method handleException (line 227) | private void handleException(Exception e) throws RemoteException {
method getPackageInfo (line 242) | @Override
method isPluginPackage (line 265) | @Override
method getActivityInfo (line 272) | @Override
method getReceiverInfo (line 290) | @Override
method getServiceInfo (line 308) | @Override
method getProviderInfo (line 327) | @Override
method shouldNotBlockOtherInfo (line 345) | private boolean shouldNotBlockOtherInfo() {
method getAndCheckCallingPkg (line 360) | private String getAndCheckCallingPkg(String pkg) {
method pkgInPid (line 373) | private boolean pkgInPid(int pid, String pkg) {
method resolveIntent (line 382) | @Override
method queryIntentActivities (line 411) | @Override
method queryIntentReceivers (line 436) | @Override
method resolveService (line 461) | @Override
method queryIntentServices (line 489) | @Override
method queryIntentContentProviders (line 514) | @Override
method getInstalledPackages (line 540) | @Override
method getInstalledApplications (line 565) | @Override
method getPermissionInfo (line 591) | @Override
method queryPermissionsByGroup (line 622) | @Override
method getPermissionGroupInfo (line 655) | @Override
method getAllPermissionGroups (line 686) | @Override
method resolveContentProvider (line 720) | @Override
method deleteApplicationCacheFiles (line 751) | @Override
method clearApplicationUserData (line 775) | @Override
method getApplicationInfo (line 799) | @Override
method installPackage (line 818) | @Override
method dexOpt (line 923) | private void dexOpt(Context hostContext, String apkfile, PluginPackage...
method saveSignatures (line 932) | private void saveSignatures(PackageInfo pkgInfo) {
method readSignatures (line 952) | private Signature[] readSignatures(String packageName) {
method sendInstalledBroadcast (line 977) | private void sendInstalledBroadcast(String packageName) {
method sendUninstalledBroadcast (line 983) | private void sendUninstalledBroadcast(String packageName) {
method copyNativeLibs (line 989) | private int copyNativeLibs(Context context, String apkfile, Applicatio...
method deletePackage (line 995) | @Override
method getReceivers (line 1017) | @Override
method getReceiverIntentFilter (line 1035) | @Override
method checkSignatures (line 1056) | @Override
method getSignature (line 1098) | private Signature[] getSignature(String pkg, PackageManager pm) throws...
method selectStubActivityInfo (line 1116) | @Override
method selectStubActivityInfoByIntent (line 1121) | @Override
method selectStubServiceInfo (line 1139) | @Override
method selectStubServiceInfoByIntent (line 1144) | @Override
method getTargetServiceInfo (line 1163) | @Override
method selectStubProviderInfo (line 1168) | @Override
method getPackageNameByPid (line 1174) | @Override
method getProcessNameByPid (line 1184) | @Override
method killBackgroundProcesses (line 1190) | @Override
method killApplicationProcess (line 1209) | @Override
method forceStopPackage (line 1214) | @Override
method registerApplicationCallback (line 1219) | @Override
method unregisterApplicationCallback (line 1224) | @Override
method onActivityCreated (line 1229) | @Override
method onActivityDestory (line 1234) | @Override
method onServiceCreated (line 1239) | @Override
method onServiceDestory (line 1244) | @Override
method onProviderCreated (line 1249) | @Override
method reportMyProcessName (line 1254) | @Override
method onDestroy (line 1259) | public void onDestroy() {
method onActivtyOnNewIntent (line 1263) | @Override
method getMyPid (line 1268) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/PluginManager.java
class PluginManager (line 66) | public class PluginManager implements ServiceConnection {
method onServiceConnected (line 96) | @Override
method onServiceDisconnected (line 147) | @Override
method waitForConnected (line 168) | public void waitForConnected() {
method waitForConnected (line 189) | public void waitForConnected(long timeout) {
method connectToService (line 211) | public void connectToService() {
method addServiceConnection (line 238) | public void addServiceConnection(ServiceConnection sc) {
method removeServiceConnection (line 242) | public void removeServiceConnection(ServiceConnection sc) {
method init (line 253) | public void init(Context hostContext) {
method getHostContext (line 258) | public Context getHostContext() {
method isConnected (line 262) | public boolean isConnected() {
method getInstance (line 266) | public static PluginManager getInstance() {
method getPackageInfo (line 276) | public PackageInfo getPackageInfo(String packageName, int flags) throw...
method isPluginPackage (line 292) | public boolean isPluginPackage(String packageName) throws RemoteExcept...
method isPluginPackage (line 314) | public boolean isPluginPackage(ComponentName className) throws RemoteE...
method getActivityInfo (line 321) | public ActivityInfo getActivityInfo(ComponentName className, int flags...
method getReceiverInfo (line 340) | public ActivityInfo getReceiverInfo(ComponentName className, int flags...
method getServiceInfo (line 358) | public ServiceInfo getServiceInfo(ComponentName className, int flags) ...
method getProviderInfo (line 376) | public ProviderInfo getProviderInfo(ComponentName className, int flags...
method resolveIntent (line 394) | public ResolveInfo resolveIntent(Intent intent, String resolvedType, i...
method resolveService (line 409) | public ResolveInfo resolveService(Intent intent, String resolvedType, ...
method queryIntentActivities (line 424) | public List<ResolveInfo> queryIntentActivities(Intent intent, String r...
method queryIntentReceivers (line 439) | public List<ResolveInfo> queryIntentReceivers(Intent intent, String re...
method queryIntentServices (line 454) | public List<ResolveInfo> queryIntentServices(Intent intent, String res...
method queryIntentContentProviders (line 469) | public List<ResolveInfo> queryIntentContentProviders(Intent intent, St...
method getInstalledPackages (line 484) | public List<PackageInfo> getInstalledPackages(int flags) throws Remote...
method getInstalledApplications (line 499) | public List<ApplicationInfo> getInstalledApplications(int flags) throw...
method getPermissionInfo (line 515) | public PermissionInfo getPermissionInfo(String name, int flags) throws...
method queryPermissionsByGroup (line 530) | public List<PermissionInfo> queryPermissionsByGroup(String group, int ...
method getPermissionGroupInfo (line 545) | public PermissionGroupInfo getPermissionGroupInfo(String name, int fla...
method getAllPermissionGroups (line 560) | public List<PermissionGroupInfo> getAllPermissionGroups(int flags) thr...
method resolveContentProvider (line 575) | public ProviderInfo resolveContentProvider(String name, Integer flags)...
method deleteApplicationCacheFiles (line 590) | public void deleteApplicationCacheFiles(String packageName, final Obje...
method clearApplicationUserData (line 618) | public void clearApplicationUserData(String packageName, final Object ...
method getApplicationInfo (line 646) | public ApplicationInfo getApplicationInfo(String packageName, int flag...
method selectStubActivityInfo (line 661) | public ActivityInfo selectStubActivityInfo(ActivityInfo pluginInfo) th...
method selectStubActivityInfo (line 676) | public ActivityInfo selectStubActivityInfo(Intent pluginInfo) throws R...
method selectStubServiceInfo (line 691) | public ServiceInfo selectStubServiceInfo(ServiceInfo pluginInfo) throw...
method selectStubServiceInfo (line 706) | public ServiceInfo selectStubServiceInfo(Intent pluginInfo) throws Rem...
method selectStubProviderInfo (line 721) | public ProviderInfo selectStubProviderInfo(String name) throws RemoteE...
method resolveActivityInfo (line 736) | public ActivityInfo resolveActivityInfo(Intent intent, int flags) thro...
method resolveServiceInfo (line 759) | public ServiceInfo resolveServiceInfo(Intent intent, int flags) throws...
method killBackgroundProcesses (line 782) | public void killBackgroundProcesses(String packageName) throws RemoteE...
method forceStopPackage (line 796) | public void forceStopPackage(String packageName) throws RemoteException {
method killApplicationProcess (line 811) | public boolean killApplicationProcess(String packageName) throws Remot...
method getReceivers (line 826) | public List<ActivityInfo> getReceivers(String packageName, int flags) ...
method getReceiverIntentFilter (line 841) | public List<IntentFilter> getReceiverIntentFilter(ActivityInfo info) t...
method getTargetServiceInfo (line 856) | public ServiceInfo getTargetServiceInfo(ServiceInfo info) throws Remot...
method installPackage (line 871) | public int installPackage(String filepath, int flags) throws RemoteExc...
method getPackageNameByPid (line 888) | public List<String> getPackageNameByPid(int pid) throws RemoteException {
method getProcessNameByPid (line 904) | public String getProcessNameByPid(int pid) throws RemoteException {
method onActivityCreated (line 919) | public void onActivityCreated(ActivityInfo stubInfo, ActivityInfo targ...
method onActivityDestory (line 933) | public void onActivityDestory(ActivityInfo stubInfo, ActivityInfo targ...
method onServiceCreated (line 947) | public void onServiceCreated(ServiceInfo stubInfo, ServiceInfo targetI...
method onServiceDestory (line 962) | public void onServiceDestory(ServiceInfo stubInfo, ServiceInfo targetI...
method onProviderCreated (line 974) | public void onProviderCreated(ProviderInfo stubInfo, ProviderInfo targ...
method reportMyProcessName (line 988) | public void reportMyProcessName(String stubProcessName, String targetP...
method deletePackage (line 1002) | public void deletePackage(String packageName, int flags) throws Remote...
method checkSignatures (line 1017) | public int checkSignatures(String pkg0, String pkg1) throws RemoteExce...
method onActivtyOnNewIntent (line 1033) | public void onActivtyOnNewIntent(ActivityInfo stubInfo, ActivityInfo t...
method getMyPid (line 1047) | public int getMyPid() throws RemoteException {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/IntentMatcher.java
class IntentMatcher (line 50) | public class IntentMatcher {
method compare (line 56) | public int compare(ResolveInfo r1, ResolveInfo r2) {
method resolveReceiverIntent (line 86) | public static final List<ResolveInfo> resolveReceiverIntent(Context co...
method resolveServiceIntent (line 137) | public static final List<ResolveInfo> resolveServiceIntent(Context con...
method resolveProviderIntent (line 189) | public static final List<ResolveInfo> resolveProviderIntent(Context co...
method resolveActivityIntent (line 240) | public static final List<ResolveInfo> resolveActivityIntent(Context co...
method resolveIntent (line 290) | public static final List<ResolveInfo> resolveIntent(Context context, M...
method queryIntentReceiverForPackage (line 361) | private static void queryIntentReceiverForPackage(Context context, Plu...
method queryIntentProviderForPackage (line 400) | private static void queryIntentProviderForPackage(Context context, Plu...
method queryIntentServiceForPackage (line 440) | private static void queryIntentServiceForPackage(Context context, Plug...
method queryIntentActivityForPackage (line 480) | private static void queryIntentActivityForPackage(Context context, Plu...
method newResolveInfo (line 520) | @TargetApi(VERSION_CODES.KITKAT)
method newResolveInfo (line 536) | private static ResolveInfo newResolveInfo(ServiceInfo serviceInfo, Int...
method newResolveInfo (line 553) | private static ResolveInfo newResolveInfo(ActivityInfo activityInfo, I...
method findBest (line 570) | public static ResolveInfo findBest(List<ResolveInfo> infos) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParser.java
class PackageParser (line 48) | abstract class PackageParser {
method PackageParser (line 53) | PackageParser(Context context) {
method newPluginParser (line 68) | public static PackageParser newPluginParser(Context context) throws Ex...
method parsePackage (line 92) | public abstract void parsePackage(File file, int flags) throws Exception;
method collectCertificates (line 94) | public abstract void collectCertificates(int flags) throws Exception;
method generateActivityInfo (line 96) | public abstract ActivityInfo generateActivityInfo(Object activity, int...
method generateServiceInfo (line 98) | public abstract ServiceInfo generateServiceInfo(Object service, int fl...
method generateProviderInfo (line 100) | public abstract ProviderInfo generateProviderInfo(Object provider, int...
method generateReceiverInfo (line 102) | public ActivityInfo generateReceiverInfo(Object receiver, int flags) t...
method generateInstrumentationInfo (line 106) | public abstract InstrumentationInfo generateInstrumentationInfo(Object...
method generateApplicationInfo (line 108) | public abstract ApplicationInfo generateApplicationInfo(int flags) thr...
method generatePermissionGroupInfo (line 110) | public abstract PermissionGroupInfo generatePermissionGroupInfo(Object...
method generatePermissionInfo (line 112) | public abstract PermissionInfo generatePermissionInfo(Object permissio...
method generatePackageInfo (line 114) | public abstract PackageInfo generatePackageInfo(int gids[], int flags,...
method getActivities (line 116) | public abstract List getActivities() throws Exception;
method getServices (line 118) | public abstract List getServices() throws Exception;
method getProviders (line 120) | public abstract List getProviders() throws Exception;
method getPermissions (line 122) | public abstract List getPermissions() throws Exception;
method getPermissionGroups (line 124) | public abstract List getPermissionGroups() throws Exception;
method getRequestedPermissions (line 126) | public abstract List getRequestedPermissions() throws Exception;
method getReceivers (line 128) | public abstract List getReceivers() throws Exception;
method getInstrumentations (line 130) | public abstract List getInstrumentations() throws Exception;
method getPackageName (line 133) | public abstract String getPackageName() throws Exception;
method readNameFromComponent (line 136) | public abstract String readNameFromComponent(Object data) throws Excep...
method readIntentFilterFromComponent (line 138) | public abstract List<IntentFilter> readIntentFilterFromComponent(Objec...
method writeSignature (line 140) | public abstract void writeSignature(Signature[] signatures) throws Exc...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi15.java
class PackageParserApi15 (line 42) | class PackageParserApi15 extends PackageParserApi20 {
method PackageParserApi15 (line 45) | public PackageParserApi15(Context context) throws Exception {
method generateActivityInfo (line 49) | @Override
method generateServiceInfo (line 57) | @Override
method generateProviderInfo (line 65) | @Override
method generateInstrumentationInfo (line 72) | @Override
method generateApplicationInfo (line 80) | @Override
method generatePermissionGroupInfo (line 87) | @Override
method generatePermissionInfo (line 96) | @Override
method generatePackageInfo (line 104) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi16.java
class PackageParserApi16 (line 44) | @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
method PackageParserApi16 (line 50) | public PackageParserApi16(Context context) throws Exception {
method generateActivityInfo (line 56) | @Override
method generateServiceInfo (line 64) | @Override
method generateProviderInfo (line 72) | @Override
method generateInstrumentationInfo (line 80) | @Override
method generateApplicationInfo (line 88) | @Override
method generatePermissionGroupInfo (line 96) | @Override
method generatePermissionInfo (line 105) | @Override
method generatePackageInfo (line 113) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi20.java
class PackageParserApi20 (line 36) | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
method PackageParserApi20 (line 40) | public PackageParserApi20(Context context) throws Exception {
method parsePackage (line 44) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi21.java
class PackageParserApi21 (line 57) | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
method PackageParserApi21 (line 77) | public PackageParserApi21(Context context) throws Exception {
method initClasses (line 83) | private void initClasses() throws ClassNotFoundException, Instantiatio...
method parsePackage (line 104) | @Override
method collectCertificates (line 111) | @Override
method generateActivityInfo (line 120) | @Override
method generateServiceInfo (line 129) | @Override
method generateProviderInfo (line 138) | @Override
method generateInstrumentationInfo (line 146) | @Override
method generateApplicationInfo (line 155) | @Override
method generatePermissionGroupInfo (line 163) | @Override
method generatePermissionInfo (line 173) | @Override
method generatePackageInfo (line 182) | @Override
method getActivities (line 230) | @Override
method getServices (line 236) | @Override
method getProviders (line 242) | @Override
method getPermissions (line 248) | @Override
method getPermissionGroups (line 254) | @Override
method getRequestedPermissions (line 260) | @Override
method getReceivers (line 266) | @Override
method getInstrumentations (line 272) | @Override
method getPackageName (line 279) | @Override
method readNameFromComponent (line 285) | @Override
method readIntentFilterFromComponent (line 290) | @Override
method writeSignature (line 295) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi22.java
class PackageParserApi22 (line 44) | @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
method PackageParserApi22 (line 48) | PackageParserApi22(Context context) throws Exception {
method generatePackageInfo (line 52) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi22Preview1.java
class PackageParserApi22Preview1 (line 40) | class PackageParserApi22Preview1 extends PackageParserApi21 {
method PackageParserApi22Preview1 (line 45) | PackageParserApi22Preview1(Context context) throws Exception {
method generatePackageInfo (line 49) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PluginPackageParser.java
class PluginPackageParser (line 57) | public class PluginPackageParser {
method PluginPackageParser (line 90) | public PluginPackageParser(Context hostContext, File pluginFile) throw...
method getPluginFile (line 227) | public File getPluginFile() {
method collectCertificates (line 231) | public void collectCertificates(int flags) throws Exception {
method getActivityIntentFilter (line 235) | public List<IntentFilter> getActivityIntentFilter(ComponentName classN...
method getServiceIntentFilter (line 241) | public List<IntentFilter> getServiceIntentFilter(ComponentName classNa...
method getProviderIntentFilter (line 248) | public List<IntentFilter> getProviderIntentFilter(ComponentName classN...
method getActivityInfo (line 255) | public ActivityInfo getActivityInfo(ComponentName className, int flags...
method getServiceInfo (line 271) | public ServiceInfo getServiceInfo(ComponentName className, int flags) ...
method getReceiverInfo (line 287) | public ActivityInfo getReceiverInfo(ComponentName className, int flags...
method getProviderInfo (line 304) | public ProviderInfo getProviderInfo(ComponentName className, int flags...
method getInstrumentationInfo (line 320) | public InstrumentationInfo getInstrumentationInfo(ComponentName classN...
method getApplicationInfo (line 331) | public ApplicationInfo getApplicationInfo(int flags) throws Exception {
method getPermissionGroupInfo (line 341) | public PermissionGroupInfo getPermissionGroupInfo(ComponentName classN...
method getPermissionInfo (line 352) | public PermissionInfo getPermissionInfo(ComponentName className, int f...
method getPackageInfo (line 363) | public PackageInfo getPackageInfo(int flags) throws Exception {
method getActivities (line 370) | public List<ActivityInfo> getActivities() throws Exception {
method getServices (line 374) | public List<ServiceInfo> getServices() throws Exception {
method getProviders (line 378) | public List<ProviderInfo> getProviders() throws Exception {
method getReceivers (line 382) | public List<ActivityInfo> getReceivers() throws Exception {
method getPermissions (line 386) | public List<PermissionInfo> getPermissions() throws Exception {
method getPermissionGroups (line 390) | public List<PermissionGroupInfo> getPermissionGroups() throws Exception {
method getInstrumentationInfos (line 394) | public List<InstrumentationInfo> getInstrumentationInfos() {
method getRequestedPermissions (line 398) | public List<String> getRequestedPermissions() throws Exception {
method getPackageName (line 404) | public String getPackageName() throws Exception {
method fixApplicationInfo (line 409) | private ApplicationInfo fixApplicationInfo(ApplicationInfo application...
method fixPackageInfo (line 493) | private PackageInfo fixPackageInfo(PackageInfo packageInfo) {
method getReceiverIntentFilter (line 500) | public Map<ActivityInfo, List<IntentFilter>> getReceiverIntentFilter() {
method getReceiverIntentFilter (line 510) | public List<IntentFilter> getReceiverIntentFilter(ActivityInfo info) {
method writeSignature (line 521) | public void writeSignature(Signature[] signatures) throws Exception {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/reflect/FieldUtils.java
class FieldUtils (line 40) | public class FieldUtils {
method getKey (line 44) | private static String getKey(Class<?> cls, String fieldName) {
method getField (line 50) | private static Field getField(Class<?> cls, String fieldName, final bo...
method readField (line 107) | public static Object readField(final Field field, final Object target,...
method writeField (line 118) | public static void writeField(final Field field, final Object target, ...
method readField (line 130) | public static Object readField(final Field field, final Object target)...
method getField (line 134) | public static Field getField(final Class<?> cls, final String fieldNam...
method readField (line 139) | public static Object readField(final Object target, final String field...
method readField (line 148) | public static Object readField(final Object target, final String field...
method writeField (line 158) | public static void writeField(final Object target, final String fieldN...
method writeField (line 162) | public static void writeField(final Object target, final String fieldN...
method writeField (line 171) | public static void writeField(final Field field, final Object target, ...
method readStaticField (line 175) | public static Object readStaticField(final Field field, final boolean ...
method readStaticField (line 181) | public static Object readStaticField(final Class<?> cls, final String ...
method writeStaticField (line 188) | public static void writeStaticField(final Field field, final Object va...
method writeStaticField (line 196) | public static void writeStaticField(final Class<?> cls, final String f...
method getDeclaredField (line 203) | public static Field getDeclaredField(final Class<?> cls, final String ...
method writeDeclaredField (line 223) | public static void writeDeclaredField(final Object target, final Strin...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/reflect/MemberUtils.java
class MemberUtils (line 34) | class MemberUtils {
method isPackageAccess (line 40) | private static boolean isPackageAccess(final int modifiers) {
method isAccessible (line 44) | static boolean isAccessible(final Member m) {
method setAccessibleWorkaround (line 48) | static boolean setAccessibleWorkaround(final AccessibleObject o) {
method isAssignable (line 64) | static boolean isAssignable(final Class<?> cls, final Class<?> toClass) {
method isAssignable (line 68) | static boolean isAssignable(Class<?>[] classArray, Class<?>[] toClassA...
method isAssignable (line 86) | static boolean isAssignable(Class<?> cls, final Class<?> toClass, fina...
method primitiveToWrapper (line 184) | static Class<?> primitiveToWrapper(final Class<?> cls) {
method wrapperToPrimitive (line 192) | static Class<?> wrapperToPrimitive(final Class<?> cls) {
method compareParameterTypes (line 196) | static int compareParameterTypes(final Class<?>[] left, final Class<?>...
method getTotalTransformationCost (line 202) | private static float getTotalTransformationCost(final Class<?>[] srcAr...
method getObjectTransformationCost (line 213) | private static float getObjectTransformationCost(Class<?> srcClass, fi...
method getPrimitivePromotionCost (line 241) | private static float getPrimitivePromotionCost(final Class<?> srcClass...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/reflect/MethodUtils.java
class MethodUtils (line 37) | public class MethodUtils {
method getKey (line 41) | private static String getKey(final Class<?> cls, final String methodNa...
method getAccessibleMethodFromSuperclass (line 55) | private static Method getAccessibleMethodFromSuperclass(final Class<?>...
method getAccessibleMethodFromInterfaceNest (line 72) | private static Method getAccessibleMethodFromInterfaceNest(Class<?> cls,
method getAccessibleMethod (line 105) | private static Method getAccessibleMethod(Method method) {
method getAccessibleMethod (line 129) | public static Method getAccessibleMethod(final Class<?> cls, final Str...
method getMatchingAccessibleMethod (line 152) | private static Method getMatchingAccessibleMethod(final Class<?> cls,
method invokeMethod (line 201) | public static Object invokeMethod(final Object object, final String me...
method invokeStaticMethod (line 217) | public static Object invokeStaticMethod(final Class clazz, final Strin...
method invokeStaticMethod (line 233) | public static Object invokeStaticMethod(final Class clazz, final Strin...
method invokeMethod (line 241) | public static Object invokeMethod(final Object object, final String me...
method invokeConstructor (line 249) | public static <T> T invokeConstructor(final Class<T> cls, Object... args)
method invokeConstructor (line 257) | public static <T> T invokeConstructor(final Class<T> cls, Object[] arg...
method getMatchingAccessibleConstructor (line 270) | public static <T> Constructor<T> getMatchingAccessibleConstructor(fina...
method getAccessibleConstructor (line 311) | private static <T> Constructor<T> getAccessibleConstructor(final Const...
method isAccessible (line 317) | private static boolean isAccessible(final Class<?> type) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/reflect/Utils.java
class Utils (line 33) | public class Utils {
method isSameLength (line 39) | static boolean isSameLength(final Object[] array1, final Object[] arra...
method toClass (line 48) | static Class<?>[] toClass(final Object... array) {
method nullToEmpty (line 61) | static Class<?>[] nullToEmpty(final Class<?>[] array) {
method nullToEmpty (line 68) | static Object[] nullToEmpty(final Object[] array) {
method getAllInterfaces (line 75) | public static List<Class<?>> getAllInterfaces(final Class<?> cls) {
method getAllInterfaces (line 84) | private static void getAllInterfaces(Class<?> cls, final HashSet<Class...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/reflect/Validate.java
class Validate (line 28) | class Validate {
method isTrue (line 30) | static void isTrue(final boolean expression, final String message, fin...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/AbstractContentProviderStub.java
class AbstractContentProviderStub (line 61) | public abstract class AbstractContentProviderStub extends ContentProvider {
method onCreate (line 68) | @Override
method buildNewUri (line 74) | private Uri buildNewUri(Uri uri, String targetAuthority) {
method getContentProviderClient (line 96) | private synchronized ContentProviderClient getContentProviderClient(fi...
method getMyAuthority (line 147) | private String getMyAuthority() throws PackageManager.NameNotFoundExce...
method query (line 164) | @Override
method handleExpcetion (line 179) | protected void handleExpcetion(Exception e) {
method getType (line 184) | @Override
method insert (line 198) | @Override
method delete (line 212) | @Override
method update (line 226) | @Override
method call (line 241) | @TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
method bulkInsert (line 258) | @Override
method applyBatch (line 272) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/AbstractServiceStub.java
class AbstractServiceStub (line 36) | public abstract class AbstractServiceStub extends Service {
method onCreate (line 43) | @Override
method onDestroy (line 49) | @Override
method startKillService (line 66) | public static void startKillService(Context context, Intent service) {
method onStart (line 71) | @Override
method startKillSelf (line 97) | private void startKillSelf() {
method handleException (line 119) | private void handleException(Throwable e) {
method onTaskRemoved (line 123) | @Override
method onBind (line 135) | @Override
method onRebind (line 147) | @Override
method onUnbind (line 159) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/ActivityStub.java
class ActivityStub (line 31) | public abstract class ActivityStub extends Activity {
class SingleInstanceStub (line 33) | private static class SingleInstanceStub extends ActivityStub {
class SingleTaskStub (line 36) | private static class SingleTaskStub extends ActivityStub {
class SingleTopStub (line 39) | private static class SingleTopStub extends ActivityStub {
class StandardStub (line 42) | private static class StandardStub extends ActivityStub {
class P00 (line 47) | public static class P00{
class SingleInstance00 (line 49) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 52) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 55) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 58) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 61) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 64) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 67) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 70) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 73) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 76) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 79) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 82) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 85) | public static class Standard00 extends StandardStub {
class P01 (line 92) | public static class P01{
class SingleInstance00 (line 94) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 97) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 100) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 103) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 106) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 109) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 112) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 115) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 118) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 121) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 124) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 127) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 130) | public static class Standard00 extends StandardStub {
class P02 (line 135) | public static class P02{
class SingleInstance00 (line 137) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 140) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 143) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 146) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 149) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 152) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 155) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 158) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 161) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 164) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 167) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 170) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 173) | public static class Standard00 extends StandardStub {
class P03 (line 179) | public static class P03{
class SingleInstance00 (line 181) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 184) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 187) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 190) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 193) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 196) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 199) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 202) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 205) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 208) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 211) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 214) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 217) | public static class Standard00 extends StandardStub {
class P04 (line 222) | public static class P04{
class SingleInstance00 (line 224) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 227) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 230) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 233) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 236) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 239) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 242) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 245) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 248) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 251) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 254) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 257) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 260) | public static class Standard00 extends StandardStub {
class P05 (line 265) | public static class P05{
class SingleInstance00 (line 267) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 270) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 273) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 276) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 279) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 282) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 285) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 288) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 291) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 294) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 297) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 300) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 303) | public static class Standard00 extends StandardStub {
class P06 (line 308) | public static class P06{
class SingleInstance00 (line 310) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 313) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 316) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 319) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 322) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 325) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 328) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 331) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 334) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 337) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 340) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 343) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 346) | public static class Standard00 extends StandardStub {
class P07 (line 351) | public static class P07{
class SingleInstance00 (line 353) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 356) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 359) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 362) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 365) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 368) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 371) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 374) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 377) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 380) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 383) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 386) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 389) | public static class Standard00 extends StandardStub {
class P08 (line 394) | public static class P08{
class SingleInstance00 (line 396) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 399) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 402) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 405) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 408) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 411) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 414) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 417) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 420) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 423) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 426) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 429) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 432) | public static class Standard00 extends StandardStub {
class Dialog (line 437) | public static class Dialog {
class P00 (line 440) | public static class P00{
class SingleInstance00 (line 442) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 445) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 448) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 451) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 454) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 457) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 460) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 463) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 466) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 469) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 472) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 475) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 478) | public static class Standard00 extends StandardStub {
class P01 (line 485) | public static class P01{
class SingleInstance00 (line 487) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 490) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 493) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 496) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 499) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 502) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 505) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 508) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 511) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 514) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 517) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 520) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 523) | public static class Standard00 extends StandardStub {
class P02 (line 528) | public static class P02{
class SingleInstance00 (line 530) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 533) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 536) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 539) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 542) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 545) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 548) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 551) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 554) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 557) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 560) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 563) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 566) | public static class Standard00 extends StandardStub {
class P03 (line 572) | public static class P03{
class SingleInstance00 (line 574) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 577) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 580) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 583) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 586) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 589) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 592) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 595) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 598) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 601) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 604) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 607) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 610) | public static class Standard00 extends StandardStub {
class P04 (line 615) | public static class P04{
class SingleInstance00 (line 617) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 620) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 623) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 626) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 629) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 632) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 635) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 638) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 641) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 644) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 647) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 650) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 653) | public static class Standard00 extends StandardStub {
class P05 (line 658) | public static class P05{
class SingleInstance00 (line 660) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 663) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 666) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 669) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 672) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 675) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 678) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 681) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 684) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 687) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 690) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 693) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 696) | public static class Standard00 extends StandardStub {
class P06 (line 701) | public static class P06{
class SingleInstance00 (line 703) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 706) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 709) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 712) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 715) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 718) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 721) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 724) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 727) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 730) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 733) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 736) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 739) | public static class Standard00 extends StandardStub {
class P07 (line 744) | public static class P07{
class SingleInstance00 (line 746) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 749) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 752) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 755) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 758) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 761) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 764) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 767) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 770) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 773) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 776) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 779) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 782) | public static class Standard00 extends StandardStub {
class P08 (line 787) | public static class P08{
class SingleInstance00 (line 789) | public static class SingleInstance00 extends SingleInstanceStub {
class SingleTask00 (line 792) | public static class SingleTask00 extends SingleTaskStub {
class SingleTop00 (line 795) | public static class SingleTop00 extends SingleTopStub {
class SingleInstance01 (line 798) | public static class SingleInstance01 extends SingleInstanceStub {
class SingleTask01 (line 801) | public static class SingleTask01 extends SingleTaskStub {
class SingleTop01 (line 804) | public static class SingleTop01 extends SingleTopStub {
class SingleInstance02 (line 807) | public static class SingleInstance02 extends SingleInstanceStub {
class SingleTask02 (line 810) | public static class SingleTask02 extends SingleTaskStub {
class SingleTop02 (line 813) | public static class SingleTop02 extends SingleTopStub {
class SingleInstance03 (line 816) | public static class SingleInstance03 extends SingleInstanceStub {
class SingleTask03 (line 819) | public static class SingleTask03 extends SingleTaskStub {
class SingleTop03 (line 822) | public static class SingleTop03 extends SingleTopStub {
class Standard00 (line 825) | public static class Standard00 extends StandardStub {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/ContentProviderStub.java
class ContentProviderStub (line 28) | public abstract class ContentProviderStub extends AbstractContentProvide...
class StubP00 (line 30) | public static class StubP00 extends ContentProviderStub {
class StubP01 (line 33) | public static class StubP01 extends ContentProviderStub {
class StubP02 (line 36) | public static class StubP02 extends ContentProviderStub {
class StubP03 (line 39) | public static class StubP03 extends ContentProviderStub {
class StubP04 (line 42) | public static class StubP04 extends ContentProviderStub {
class StubP05 (line 45) | public static class StubP05 extends ContentProviderStub {
class StubP06 (line 48) | public static class StubP06 extends ContentProviderStub {
class StubP07 (line 51) | public static class StubP07 extends ContentProviderStub {
class StubP08 (line 54) | public static class StubP08 extends ContentProviderStub {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/MyFakeIBinder.java
class MyFakeIBinder (line 35) | public class MyFakeIBinder implements IBinder {
method getInterfaceDescriptor (line 37) | @Override
method pingBinder (line 42) | @Override
method isBinderAlive (line 47) | @Override
method queryLocalInterface (line 52) | @Override
method dump (line 57) | @Override
method dumpAsync (line 62) | @Override
method transact (line 67) | @Override
method linkToDeath (line 72) | @Override
method unlinkToDeath (line 77) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/ServcesManager.java
class ServcesManager (line 53) | public class ServcesManager {
method ServcesManager (line 59) | private ServcesManager() {
method getDefault (line 64) | public static ServcesManager getDefault() {
method hasServiceRunning (line 73) | public boolean hasServiceRunning() {
method findTokenByService (line 77) | private Object findTokenByService(Service service) {
method getClassLoader (line 86) | private ClassLoader getClassLoader(ApplicationInfo pluginApplicationIn...
method handleCreateServiceOne (line 102) | private void handleCreateServiceOne(Context hostContext, Intent stubIn...
method handleOnStartOne (line 147) | private void handleOnStartOne(Intent intent, int flags, int startIds) ...
method handleOnTaskRemovedOne (line 167) | private void handleOnTaskRemovedOne(Intent intent) throws Exception {
method handleOnDestroyOne (line 184) | private void handleOnDestroyOne(ServiceInfo targetInfo) {
method handleOnBindOne (line 200) | private IBinder handleOnBindOne(Intent intent) throws Exception {
method handleOnRebindOne (line 213) | private void handleOnRebindOne(Intent intent) throws Exception {
method handleOnUnbindOne (line 225) | private boolean handleOnUnbindOne(Intent intent) throws Exception {
method onStart (line 239) | public int onStart(Context context, Intent intent, int flags, int star...
method onTaskRemoved (line 255) | public void onTaskRemoved(Context context, Intent intent) throws Excep...
method onBind (line 267) | public IBinder onBind(Context context, Intent intent) throws Exception {
method onRebind (line 280) | public void onRebind(Context context, Intent intent) throws Exception {
method onUnbind (line 292) | public boolean onUnbind(Intent intent) throws Exception {
method stopService (line 305) | public int stopService(Context context, Intent intent) throws Exception {
method stopServiceToken (line 315) | public boolean stopServiceToken(ComponentName cn, IBinder token, int s...
method onDestroy (line 337) | public void onDestroy() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/ServiceStub.java
class ServiceStub (line 26) | public abstract class ServiceStub extends AbstractServiceStub {
class StubP00 (line 29) | public abstract static class StubP00 extends ServiceStub {
class P00 (line 30) | public static class P00 extends StubP00 {
class StubP01 (line 34) | public abstract static class StubP01 extends ServiceStub {
class P00 (line 35) | public static class P00 extends StubP01 {
class StubP02 (line 39) | public abstract static class StubP02 extends ServiceStub {
class P00 (line 40) | public static class P00 extends StubP01 {
class StubP03 (line 44) | public abstract static class StubP03 extends ServiceStub {
class P00 (line 45) | public static class P00 extends StubP01 {
class StubP04 (line 49) | public abstract static class StubP04 extends ServiceStub {
class P00 (line 50) | public static class P00 extends StubP01 {
class StubP05 (line 54) | public abstract static class StubP05 extends ServiceStub {
class P00 (line 55) | public static class P00 extends StubP01 {
class StubP06 (line 59) | public abstract static class StubP06 extends ServiceStub {
class P00 (line 60) | public static class P00 extends StubP01 {
class StubP07 (line 64) | public abstract static class StubP07 extends ServiceStub {
class P00 (line 65) | public static class P00 extends StubP01 {
class StubP08 (line 69) | public abstract static class StubP08 extends ServiceStub {
class P00 (line 70) | public static class P00 extends StubP01 {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/ShortcutProxyActivity.java
class ShortcutProxyActivity (line 39) | public class ShortcutProxyActivity extends Activity {
method onCreate (line 41) | @Override
method execStartForwordIntent (line 76) | protected void execStartForwordIntent(Intent forwordIntent) {
method isPlugin (line 80) | private boolean isPlugin(Intent intent) {
method waitAndStart (line 95) | private void waitAndStart(final Intent forwordIntent) {
method getForwarIntent (line 114) | private Intent getForwarIntent() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/AttributeCache.java
class AttributeCache (line 36) | public final class AttributeCache {
class Package (line 44) | public final static class Package {
method Package (line 49) | public Package(Context c) {
class Entry (line 54) | public final static class Entry {
method Entry (line 58) | public Entry(Context c, TypedArray ta) {
method init (line 64) | public static void init(Context context) {
method instance (line 70) | public static AttributeCache instance() {
method AttributeCache (line 74) | public AttributeCache(Context context) {
method removePackage (line 78) | public void removePackage(String packageName) {
method updateConfiguration (line 84) | public void updateConfiguration(Configuration config) {
method get (line 98) | public Entry get(String packageName, int resId, int[] styleable) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/ComponentNameComparator.java
class ComponentNameComparator (line 30) | public class ComponentNameComparator implements Comparator<ComponentName> {
method compare (line 32) | @Override
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/Log.java
class Log (line 42) | public class Log {
method Log (line 59) | private Log() {
method isDebug (line 68) | public static boolean isDebug() {
method isFileLog (line 72) | private static boolean isFileLog() {
method isLoggable (line 76) | public static boolean isLoggable(int i) {
method isLoggable (line 80) | public static boolean isLoggable() {
method levelToStr (line 84) | private static String levelToStr(int level) {
method getLogFile (line 103) | private static File getLogFile() {
method logToFile (line 121) | private static void logToFile(final int level, final String tag, final...
method logToFileInner (line 130) | private static void logToFileInner(int level, String tag, String forma...
method getProcessName (line 166) | private static String getProcessName() {
method println (line 170) | private static void println(final int level, final String tag, final S...
method v (line 185) | public static void v(String tag, String format, Object... args) {
method v (line 189) | public static void v(String tag, String format, Throwable tr, Object.....
method d (line 198) | public static void d(String tag, String format, Object... args) {
method d (line 202) | public static void d(String tag, String format, Throwable tr, Object.....
method i (line 209) | public static void i(String tag, String format, Object... args) {
method i (line 213) | public static void i(String tag, String format, Throwable tr, Object.....
method w (line 220) | public static void w(String tag, String format, Object... args) {
method w (line 224) | public static void w(String tag, String format, Throwable tr, Object.....
method w (line 231) | public static void w(String tag, Throwable tr) {
method e (line 235) | public static void e(String tag, String format, Object... args) {
method e (line 239) | public static void e(String tag, String format, Throwable tr, Object.....
method wtf (line 246) | public static void wtf(String tag, String format, Object... args) {
method wtf (line 250) | public static void wtf(String tag, Throwable tr) {
method wtf (line 254) | public static void wtf(String tag, String format, Throwable tr, Object...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/MyProxy.java
class MyProxy (line 33) | public class MyProxy {
method newProxyInstance (line 35) | public static Object newProxyInstance(ClassLoader loader, Class<?>[] i...
method isMethodDeclaredThrowable (line 44) | public static boolean isMethodDeclaredThrowable(Method method, Throwab...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/Utils.java
class Utils (line 43) | public class Utils {
method validateJavaIdentifier (line 51) | public static boolean validateJavaIdentifier(String identifier) {
method copyFile (line 56) | public static void copyFile(String src, String dst) throws IOException {
method deleteDir (line 84) | public static void deleteDir(String file) {
method deleteFile (line 88) | private static void deleteFile(File file) {
method writeToFile (line 98) | public static void writeToFile(File file, byte[] data) throws IOExcept...
method readFromFile (line 113) | public static byte[] readFromFile(File file) throws IOException {
method md5 (line 136) | public static String md5(byte[] data) {
method toHex (line 147) | private static String toHex(byte[] b) {
method getProcessName (line 163) | public static String getProcessName(Context context, int pid) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ActivityManagerCompat.java
class ActivityManagerCompat (line 28) | public class ActivityManagerCompat {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ActivityManagerNativeCompat.java
class ActivityManagerNativeCompat (line 32) | public class ActivityManagerNativeCompat {
method Class (line 36) | public static Class Class() throws ClassNotFoundException {
method getDefault (line 43) | public static Object getDefault() throws ClassNotFoundException, NoSuc...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ActivityThreadCompat.java
class ActivityThreadCompat (line 37) | public class ActivityThreadCompat {
method currentActivityThread (line 43) | public synchronized static final Object currentActivityThread() throws...
method activityThreadClass (line 53) | public static final Class activityThreadClass() throws ClassNotFoundEx...
method currentActivityThread2 (line 60) | private static Object currentActivityThread2() {
method getInstrumentation (line 89) | public static Instrumentation getInstrumentation() throws NoSuchMethod...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/BuildCompat.java
class BuildCompat (line 30) | public class BuildCompat {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/BundleCompat.java
class BundleCompat (line 12) | public class BundleCompat {
method getBinder (line 30) | public static IBinder getBinder(Bundle bundle, String key) {
method putBinder (line 45) | public static void putBinder(Bundle bundle, String key, IBinder value) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/CompatibilityInfoCompat.java
class CompatibilityInfoCompat (line 30) | public class CompatibilityInfoCompat {
method getMyClass (line 34) | private static Class getMyClass() throws ClassNotFoundException {
method DEFAULT_COMPATIBILITY_INFO (line 43) | public static Object DEFAULT_COMPATIBILITY_INFO() throws IllegalAccess...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ContentProviderCompat.java
class ContentProviderCompat (line 15) | public class ContentProviderCompat {
method call (line 17) | public static Bundle call(Context context, Uri uri, String method, Str...
method acquireContentProviderClient (line 34) | private static ContentProviderClient acquireContentProviderClient(Cont...
method crazyAcquireContentProvider (line 41) | public static ContentProviderClient crazyAcquireContentProvider(Contex...
method crazyAcquireContentProvider (line 54) | public static ContentProviderClient crazyAcquireContentProvider(Contex...
method acquireContentProviderClient (line 67) | private static ContentProviderClient acquireContentProviderClient(Cont...
method releaseQuietly (line 74) | public static void releaseQuietly(ContentProviderClient client) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ContentProviderHolderCompat.java
class ContentProviderHolderCompat (line 33) | public class ContentProviderHolderCompat {
method Class (line 37) | public static Class Class() throws ClassNotFoundException {
method newInstance (line 44) | public static Object newInstance(Object target) throws NoSuchMethodExc...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IActivityManagerCompat.java
class IActivityManagerCompat (line 28) | public class IActivityManagerCompat {
method Class (line 32) | public static Class Class() throws ClassNotFoundException {
method isIActivityManager (line 39) | public static boolean isIActivityManager(Object obj){
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IAppOpsServiceCompat.java
class IAppOpsServiceCompat (line 33) | public class IAppOpsServiceCompat {
method Class (line 37) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 44) | public static Object asInterface(IBinder binder) throws ClassNotFoundE...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IAudioServiceCompat.java
class IAudioServiceCompat (line 34) | public class IAudioServiceCompat {
method Class (line 38) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 45) | public static Object asInterface( IBinder binder) throws ClassNotFound...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IClipboardCompat.java
class IClipboardCompat (line 34) | public class IClipboardCompat {
method Class (line 38) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 45) | public static Object asInterface( IBinder binder) throws ClassNotFound...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IContentServiceCompat.java
class IContentServiceCompat (line 34) | public class IContentServiceCompat {
method Class (line 39) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 46) | public static Object asInterface( IBinder binder) throws ClassNotFound...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IDisplayManagerCompat.java
class IDisplayManagerCompat (line 15) | public class IDisplayManagerCompat {
method Class (line 19) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 26) | public static Object asInterface(IBinder binder) throws ClassNotFoundE...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IGraphicsStatsCompat.java
class IGraphicsStatsCompat (line 34) | public class IGraphicsStatsCompat {
method Class (line 38) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 45) | public static Object asInterface( IBinder binder) throws ClassNotFound...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IInputMethodManagerCompat.java
class IInputMethodManagerCompat (line 34) | public class IInputMethodManagerCompat {
method Class (line 38) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 45) | public static Object asInterface( IBinder binder) throws ClassNotFound...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ILocationManagerCompat.java
class ILocationManagerCompat (line 34) | public class ILocationManagerCompat {
method Class (line 38) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 45) | public static Object asInterface( IBinder binder) throws ClassNotFound...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IMediaRouterServiceCompat.java
class IMediaRouterServiceCompat (line 34) | public class IMediaRouterServiceCompat {
method Class (line 38) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 45) | public static Object asInterface( IBinder binder) throws ClassNotFound...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IMmsCompat.java
class IMmsCompat (line 33) | public class IMmsCompat {
method Class (line 37) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 44) | public static Object asInterface(IBinder binder) throws ClassNotFoundE...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IMountServiceCompat.java
class IMountServiceCompat (line 33) | public class IMountServiceCompat {
method Class (line 37) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 44) | public static Object asInterface( IBinder binder) throws ClassNotFound...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/INotificationManagerCompat.java
class INotificationManagerCompat (line 34) | public class INotificationManagerCompat {
method Class (line 38) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 45) | public static Object asInterface( IBinder binder) throws ClassNotFound...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IPackageDataObserverCompat.java
class IPackageDataObserverCompat (line 28) | public class IPackageDataObserverCompat {
method Class (line 32) | public static Class Class() throws ClassNotFoundException {
method isIPackageDataObserver (line 39) | public static boolean isIPackageDataObserver(Object obj) throws ClassN...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IPhoneSubInfoCompat.java
class IPhoneSubInfoCompat (line 33) | public class IPhoneSubInfoCompat {
method Class (line 37) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 44) | public static Object asInterface(IBinder binder) throws ClassNotFoundE...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ISearchManagerCompat.java
class ISearchManagerCompat (line 33) | public class ISearchManagerCompat {
method Class (line 37) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 44) | public static Object asInterface(IBinder binder) throws ClassNotFoundE...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ISessionManagerCompat.java
class ISessionManagerCompat (line 34) | public class ISessionManagerCompat {
method Class (line 37) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 44) | public static Object asInterface(IBinder binder) throws ClassNotFoundE...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ISmsCompat.java
class ISmsCompat (line 33) | public class ISmsCompat {
method Class (line 37) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 44) | public static Object asInterface(IBinder binder) throws ClassNotFoundE...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ISubCompat.java
class ISubCompat (line 33) | public class ISubCompat {
method Class (line 37) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 44) | public static Object asInterface(IBinder binder) throws ClassNotFoundE...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ITelephonyCompat.java
class ITelephonyCompat (line 33) | public class ITelephonyCompat {
method Class (line 36) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 43) | public static Object asInterface(IBinder binder) throws ClassNotFoundE...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ITelephonyRegistryCompat.java
class ITelephonyRegistryCompat (line 33) | public class ITelephonyRegistryCompat {
method Class (line 37) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 44) | public static Object asInterface(IBinder binder) throws ClassNotFoundE...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IWifiManagerCompat.java
class IWifiManagerCompat (line 34) | public class IWifiManagerCompat {
method Class (line 38) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 45) | public static Object asInterface(IBinder binder) throws ClassNotFoundE...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IWindowManagerCompat.java
class IWindowManagerCompat (line 34) | public class IWindowManagerCompat {
method Class (line 38) | public static Class Class() throws ClassNotFoundException {
method asInterface (line 45) | public static Object asInterface( IBinder binder) throws ClassNotFound...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/NativeLibraryHelperCompat.java
class NativeLibraryHelperCompat (line 18) | public class NativeLibraryHelperCompat {
method nativeLibraryHelperClass (line 22) | private static final Class nativeLibraryHelperClass() throws ClassNotF...
method handleClass (line 26) | private static final Class handleClass() throws ClassNotFoundException {
method copyNativeBinaries (line 30) | public static final int copyNativeBinaries(File apkFile, File sharedLi...
method copyNativeBinariesBeforeL (line 40) | private static int copyNativeBinariesBeforeL(File apkFile, File shared...
method copyNativeBinariesAfterL (line 59) | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
method isVM64 (line 119) | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
method getAbisFromApk (line 139) | private static Set<String> getAbisFromApk(String apk) {
method getHostApk (line 164) | private static String getHostApk() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/PackageManagerCompat.java
class PackageManagerCompat (line 28) | public class PackageManagerCompat {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ParceledListSliceCompat.java
class ParceledListSliceCompat (line 28) | public class ParceledListSliceCompat {
method Class (line 32) | public static Class Class() throws ClassNotFoundException {
method isParceledListSlice (line 39) | public static boolean isParceledListSlice(Object obj){
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ProcessCompat.java
class ProcessCompat (line 32) | public class ProcessCompat {
method setArgV0 (line 34) | public static final void setArgV0(String name) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/QueuedWorkCompat.java
class QueuedWorkCompat (line 32) | public class QueuedWorkCompat {
method Class (line 36) | private static Class Class() throws ClassNotFoundException {
method waitToFinish (line 43) | public static void waitToFinish() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ServiceManagerCompat.java
class ServiceManagerCompat (line 34) | public class ServiceManagerCompat {
method Class (line 38) | public static final Class Class() throws ClassNotFoundException {
method getService (line 46) | public static IBinder getService(String name) throws ClassNotFoundExce...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/SingletonCompat.java
class SingletonCompat (line 32) | public class SingletonCompat {
method Class (line 36) | public static Class Class() throws ClassNotFoundException {
method isSingleton (line 43) | public static boolean isSingleton(Object obj) {
method get (line 57) | public static Object get(Object targetSingleton) throws NoSuchMethodEx...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/SystemPropertiesCompat.java
class SystemPropertiesCompat (line 32) | public class SystemPropertiesCompat {
method getMyClass (line 36) | private static Class getMyClass() throws ClassNotFoundException {
method getInner (line 43) | private static String getInner(String key, String defaultValue) throws...
method get (line 48) | public static String get(String key, String defaultValue) {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/UserHandleCompat.java
class UserHandleCompat (line 34) | public class UserHandleCompat {
method getCallingUserId (line 37) | public static int getCallingUserId() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/VMRuntimeCompat.java
class VMRuntimeCompat (line 33) | public class VMRuntimeCompat {
method is64Bit (line 37) | public final static boolean is64Bit() {
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/WebViewFactoryCompat.java
class WebViewFactoryCompat (line 31) | public class WebViewFactoryCompat {
method Class (line 35) | public static Class Class() throws ClassNotFoundException {
method getProvider (line 42) | public static Object getProvider() throws NoSuchMethodException, Illeg...
FILE: project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/utils/ProcessUtils.java
class ProcessUtils (line 12) | public class ProcessUtils {
method isPluginProcess (line 17) | @Override
method isManagerProcess (line 22) | @Override
method setProcessChecker (line 29) | public static void setProcessChecker(IProcessChecker sIProcessChecker) {
method getProcessChecker (line 33) | public static IProcessChecker getProcessChecker() {
type IProcessChecker (line 37) | public interface IProcessChecker {
method isPluginProcess (line 38) | boolean isPluginProcess(String processName);
method isManagerProcess (line 40) | boolean isManagerProcess(String processName);
method isPluginProcess (line 43) | public static boolean isPluginProcess(Context context) {
method isManagerProcess (line 48) | public static boolean isManagerProcess(Context context) {
method isMainProcess (line 53) | public static boolean isMainProcess(Context context) {
method getProcessName (line 59) | private static String getProcessName(Context context) {
FILE: project/Test/ApiTest/src/main/cpp/Core.cpp
function registerNativeMethodsAndSetup (line 13) | int registerNativeMethodsAndSetup(JNIEnv* env) {
function __BEGIN_DECLS (line 26) | __BEGIN_DECLS
FILE: project/Test/ApiTest/src/main/cpp/HelperJni/HelperJni.cpp
function nativePing (line 23) | int nativePing(JNIEnv* env, jobject obj) {
function tryRegisterNativeMethodsHelperJni (line 32) | int tryRegisterNativeMethodsHelperJni(JNIEnv* env, const char* clazzname) {
FILE: project/Test/ApiTest/src/main/cpp/HelperJni/HelperJni.h
function clearJniExpcetion (line 15) | inline bool clearJniExpcetion(JNIEnv* env, const char *tag, const char* ...
FILE: project/Test/ApiTest/src/main/cpp/help/log.h
function android_log_print (line 45) | inline void android_log_print(int prio, const char *file, const char* func,
FILE: project/Test/ApiTest/src/main/cpp/help/nativehelper/JNIHelp.cpp
class scoped_local_ref (line 32) | class scoped_local_ref {
method scoped_local_ref (line 34) | scoped_local_ref(C_JNIEnv* env, T localRef = NULL) :
method reset (line 42) | void reset(T localRef = NULL) {
method T (line 49) | T get() const {
function jclass (line 62) | static jclass findClass(C_JNIEnv* env, const char* className) {
function jniRegisterNativeMethods (line 67) | int jniRegisterNativeMethods(C_JNIEnv* env, const char* className,
function jniRegisterNativeMethods2 (line 92) | int jniRegisterNativeMethods2(C_JNIEnv* env, const char* className,
function getExceptionSummary (line 132) | static bool getExceptionSummary(C_JNIEnv* env, jthrowable exception,
function getStackTrace (line 188) | static bool getStackTrace(C_JNIEnv* env, jthrowable exception,
function jniThrowException (line 253) | int jniThrowException(C_JNIEnv* env, const char* className, const char* ...
function jniThrowExceptionFmt (line 286) | int jniThrowExceptionFmt(C_JNIEnv* env, const char* className, const cha...
function jniThrowNullPointerException (line 293) | int jniThrowNullPointerException(C_JNIEnv* env, const char* msg) {
function jniThrowRuntimeException (line 297) | int jniThrowRuntimeException(C_JNIEnv* env, const char* msg) {
function jniThrowIOException (line 301) | int jniThrowIOException(C_JNIEnv* env, int errnum) {
function jniGetStackTrace (line 307) | static std::string jniGetStackTrace(C_JNIEnv* env, jthrowable exception) {
function jniLogException (line 336) | void jniLogException(C_JNIEnv* env, int priority, const char* tag,
function jobject (line 359) | jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd) {
function jniGetFDFromFileDescriptor (line 373) | int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor) {
function jniSetFileDescriptorOfFD (line 384) | void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor,
function jobject (line 392) | jobject jniGetReferent(C_JNIEnv* env, jobject ref) {
FILE: project/Test/ApiTest/src/main/cpp/help/nativehelper/JNIHelp.h
function jniRegisterNativeMethods (line 130) | inline int jniRegisterNativeMethods(JNIEnv* env, const char* className,
function jniRegisterNativeMethods2 (line 136) | inline int jniRegisterNativeMethods2(JNIEnv* env, const char* className,
function jniThrowException (line 142) | inline int jniThrowException(JNIEnv* env, const char* className,
function jniThrowExceptionFmt (line 154) | inline int jniThrowExceptionFmt(JNIEnv* env, const char* className,
function jniThrowNullPointerException (line 163) | inline int jniThrowNullPointerException(JNIEnv* env, const char* msg) {
function jniThrowRuntimeException (line 167) | inline int jniThrowRuntimeException(JNIEnv* env, const char* msg) {
function jniThrowIOException (line 171) | inline int jniThrowIOException(JNIEnv* env, int errnum) {
function jobject (line 175) | inline jobject jniCreateFileDescriptor(JNIEnv* env, int fd) {
function jniGetFDFromFileDescriptor (line 179) | inline int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescripto...
function jniSetFileDescriptorOfFD (line 183) | inline void jniSetFileDescriptorOfFD(JNIEnv* env, jobject fileDescriptor,
function jobject (line 188) | inline jobject jniGetReferent(JNIEnv* env, jobject ref) {
FILE: project/Test/ApiTest/src/main/java/com/example/ApiTest/ActivityTestActivity.java
class ActivityTestActivity (line 10) | public class ActivityTestActivity extends AppCompatActivity implements V...
method onCreate (line 12) | @Override
method onClick (line 22) | @Override
method onActivityResult (line 36) | @Override
FILE: project/Test/ApiTest/src/main/java/com/example/ApiTest/BaseService.java
class BaseService (line 12) | public abstract class BaseService extends Service {
method getTag (line 15) | abstract String getTag();
method onBind (line 17) | @Override
method onUnbind (line 25) | @Override
method onCreate (line 33) | @Override
method onStart (line 41) | @Override
method onStartCommand (line 49) | @Override
method onDestroy (line 57) | @Override
method onRebind (line 65) | @Override
FILE: project/Test/ApiTest/src/main/java/com/example/ApiTest/BroadcastReceiverTest.java
class BroadcastReceiverTest (line 17) | public class BroadcastReceiverTest extends AppCompatActivity implements ...
method onCreate (line 18) | @Override
class MyBroadcastReceiver (line 28) | private static class MyBroadcastReceiver extends BroadcastReceiver {
method send (line 32) | public static void send(Context c) {
method reg (line 37) | public static void reg(Context c, MyBroadcastReceiver re) {
method unreg (line 43) | public static void unreg(Context c, MyBroadcastReceiver re) {
method onReceive (line 47) | @Override
method onClick (line 57) | @Override
FILE: project/Test/ApiTest/src/main/java/com/example/ApiTest/ContentProviderTest.java
class ContentProviderTest (line 17) | public class ContentProviderTest extends AppCompatActivity implements On...
method onCreate (line 20) | @Override
method onClick (line 33) | @Override
method getsUri (line 80) | protected Uri getsUri() {
FILE: project/Test/ApiTest/src/main/java/com/example/ApiTest/ContentProviderTest2.java
class ContentProviderTest2 (line 9) | public class ContentProviderTest2 extends ContentProviderTest {
method onCreate (line 10) | @Override
method getsUri (line 16) | protected Uri getsUri() {
FILE: project/Test/Api
Condensed preview — 270 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,721K chars).
[
{
"path": ".gitignore",
"chars": 299,
"preview": "/project/Libraries/DroidPlugin/gen\n/project/Libraries/DroidPlugin/bin\n/project/Test/ApiTest/gen\n/project/Test/ApiTest/bi"
},
{
"path": "DOC/.gitignore",
"chars": 10,
"preview": ".DS_Store\n"
},
{
"path": "DOC/hejunlin/LICENSE",
"chars": 7652,
"preview": " GNU LESSER GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007"
},
{
"path": "DOC/hejunlin/插件占坑,四大组件动态注册前奏(一) 系统Activity的启动流程.md",
"chars": 20549,
"preview": "前言:为什么要了解系统Activity,Service,,BroadCastReceiver,ContentProvider的启动流程,这是一个对于即将理解插件中的四大组件动态注册,占坑的前提,如果不了解的话,那么很难了解插件hook哪些东"
},
{
"path": "DOC/hejunlin/插件占坑,四大组件动态注册前奏(三) 系统BroadCast的注册发送流程.md",
"chars": 2613,
"preview": "前言:为什么要了解系统Activity,Service,BroadCastReceiver,ContentProvider的启动流程,这是一个对于即将理解插件中的四大组件动态注册,占坑的前提,如果不了解的话,那么很难了解插件hook哪些东西"
},
{
"path": "DOC/hejunlin/插件占坑,四大组件动态注册前奏(二) 系统Service的启动流程.md",
"chars": 1748,
"preview": "\r\n前言:为什么要了解系统Activity,Service,BroadCastReceiver,ContentProvider的启动流程,这是一个对于即将理解插件中的四大组件动态注册,占坑的前提,如果不了解的话,那么很难了解插件hook哪些"
},
{
"path": "DOC/hejunlin/插件开发之360 DroidPlugin源码分析(一)初识.md",
"chars": 1915,
"preview": "插件开发之360 DroidPlugin源码分析(一)初识\r\n\r\n###DroidPlugin的是什么?\r\n\r\n 一种新的插件机制,一种免安装的运行机制,是一个沙箱(但是不完全的沙箱。就是对于使用者来说,并不知道他会把apk怎么样"
},
{
"path": "DOC/hejunlin/插件开发之360 DroidPlugin源码分析(三)Binder代理.md",
"chars": 1898,
"preview": "\r\n\r\n- **Hook机制中Binder代理类关系图**\r\n- **Hook机制中Binder代理时序图**\r\n- **MyServiceManager**\r\n- **ServiceManagerCacheBinderHook**\r\n-"
},
{
"path": "DOC/hejunlin/插件开发之360 DroidPlugin源码分析(二)Hook机制.md",
"chars": 2096,
"preview": "前言:新插件的开发,可以说是为插件开发者带来了福音,虽然还很多坑要填补,对于这款牛逼的插件机制,一直想找个时间分析和总结下它的code,话不多说,直接入正题,本文是分析../hook/handle及../hook/proxy下代码,../h"
},
{
"path": "DOC/hejunlin/插件开发之360 DroidPlugin源码分析(五)Service预注册占坑.md",
"chars": 5198,
"preview": "在了解系统的activity,service,broadcastReceiver的启动过程后,今天将分析下360 DroidPlugin是如何预注册占坑的?本篇文章主要分析Service预注册占坑,Service占了坑后又是什么时候开始瞒天"
},
{
"path": "DOC/hejunlin/插件开发之360 DroidPlugin源码分析(四)Activity预注册占坑.md",
"chars": 6157,
"preview": "在了解系统的activity,service,broadcastReceiver的启动过程后,今天将分析下360 DroidPlugin是如何预注册占坑的?本篇文章主要分析Activity预注册占坑,Activity占了坑后又是什么时候开始"
},
{
"path": "DOC/tianweishu/.gitignore",
"chars": 10,
"preview": ".DS_Store\n"
},
{
"path": "DOC/tianweishu/Activity生命周期管理.md",
"chars": 20258,
"preview": "# Activity生命周期管理\n\n之前的 [Android插件化原理解析][1] 系列文章揭开了Hook机制的神秘面纱,现在我们手握倚天屠龙,那么如何通过这种技术完成插件化方案呢?具体来说,插件中的Activity,Service等组件如"
},
{
"path": "DOC/tianweishu/BroadcastReceiver插件化.md",
"chars": 14484,
"preview": "# BroadcastReceiver插件化\n\n在[Activity生命周期管理][1] 以及 [插件加载机制][2] 中我们详细讲述了插件化过程中对于Activity组件的处理方式,为了实现Activity的插件化我们付出了相当多的努力;"
},
{
"path": "DOC/tianweishu/ClassLoader管理.md",
"chars": 29150,
"preview": "# 插件加载机制\n\n上文 [Activity生命周期管理][3] 中我们地完成了『启动没有在AndroidManifest.xml中显式声明的Activity』的任务;通过Hook `AMS`和拦截ActivityThread中`H`类对于"
},
{
"path": "DOC/tianweishu/ContentProvider插件化.md",
"chars": 27130,
"preview": "# ContentProvider插件化\n\n目前为止我们已经完成了Android四大组件中Activity,Service以及BroadcastReceiver的插件化,这几个组件各不相同,我们根据它们的特点定制了不同的插件化方案;那么对于"
},
{
"path": "DOC/tianweishu/Hook机制之AMS&PMS.md",
"chars": 11749,
"preview": "# Hook机制之AMS&PMS\n\n在前面的文章中我们介绍了DroidPlugin的Hook机制,也就是**代理方式**和**Binder Hook**;插件框架通过AOP实现了插件使用和开发的透明性。在讲述DroidPlugin如何实现四"
},
{
"path": "DOC/tianweishu/Hook机制之Binder-Hook.md",
"chars": 11064,
"preview": "# Hook机制之Binder-Hook\n\nAndroid系统通过Binder机制给应用程序提供了一系列的系统服务,诸如`ActivityManagerService`,`ClipboardManager`, `AudioManager`等"
},
{
"path": "DOC/tianweishu/Hook机制之代理Hook.md",
"chars": 7367,
"preview": "# Hook机制之动态代理\n\n使用代理机制进行API Hook进而达到方法增强是框架的常用手段,比如J2EE框架Spring通过动态代理优雅地实现了AOP编程,极大地提升了Web开发效率;同样,插件框架也广泛使用了代理机制来增强系统API从"
},
{
"path": "DOC/tianweishu/Service插件化.md",
"chars": 30991,
"preview": "# Service插件化\n\n在 [Activity生命周期管理][1] 以及 [广播的管理][2] 中我们详细探讨了Android系统中的Activity、BroadcastReceiver组件的工作原理以及它们的插件化方案,相信读者已经对"
},
{
"path": "DOC/tianweishu/概述.md",
"chars": 1927,
"preview": "# 概要\n\n2015年是Android插件化技术突飞猛进的一年,随着业务的发展各大厂商都碰到了Android Native平台的瓶颈:\n\n1. 从技术上讲,业务逻辑的复杂导致代码量急剧膨胀,各大厂商陆续出到65535方法数的天花板;同时,运"
},
{
"path": "LICENSE",
"chars": 7652,
"preview": " GNU LESSER GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007"
},
{
"path": "project/.gitignore",
"chars": 12,
"preview": "/build\n/bin\n"
},
{
"path": "project/Libraries/DroidPlugin/LICENSE.txt",
"chars": 7651,
"preview": " GNU LESSER GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007"
},
{
"path": "project/Libraries/DroidPlugin/build.gradle",
"chars": 735,
"preview": "apply plugin: 'com.android.library'\n\ndependencies {\n compileOnly fileTree(dir: 'lib', include: '*.jar')\n implement"
},
{
"path": "project/Libraries/DroidPlugin/proguard-project.txt",
"chars": 783,
"preview": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in t"
},
{
"path": "project/Libraries/DroidPlugin/project.properties",
"chars": 563,
"preview": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# T"
},
{
"path": "project/Libraries/DroidPlugin/src/main/AndroidManifest.xml",
"chars": 213056,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangy"
},
{
"path": "project/Libraries/DroidPlugin/src/main/aidl/android/app/IServiceConnection.aidl",
"chars": 860,
"preview": "/* //device/java/android/android/app/IServiceConnection.aidl\n**\n** Copyright 2007, The Android Open Source Project\n**\n**"
},
{
"path": "project/Libraries/DroidPlugin/src/main/aidl/com/morgoo/droidplugin/pm/IApplicationCallback.aidl",
"chars": 1143,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/aidl/com/morgoo/droidplugin/pm/IPackageDataObserver.aidl",
"chars": 1165,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/aidl/com/morgoo/droidplugin/pm/IPluginManager.aidl",
"chars": 5258,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/MyCrashHandler.java",
"chars": 7919,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/PluginApplication.java",
"chars": 1451,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/PluginHelper.java",
"chars": 6857,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/PluginManagerService.java",
"chars": 3039,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/PluginPatchManager.java",
"chars": 2635,
"preview": "package com.morgoo.droidplugin;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.co"
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/PluginServiceProvider.java",
"chars": 1719,
"preview": "package com.morgoo.droidplugin;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport an"
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/BaseActivityManagerService.java",
"chars": 5782,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/MyActivityManagerService.java",
"chars": 22154,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/RunningActivities.java",
"chars": 7095,
"preview": "package com.morgoo.droidplugin.am;\n\nimport android.app.Activity;\nimport android.app.LocalActivityManager;\nimport android"
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/RunningProcessList.java",
"chars": 24493,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/ServiceStubMap.java",
"chars": 3588,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/am/StaticProcessList.java",
"chars": 10897,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/core/Env.java",
"chars": 1755,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/core/PluginClassLoader.java",
"chars": 2666,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/core/PluginDirHelper.java",
"chars": 5546,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/core/PluginProcessManager.java",
"chars": 20910,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/BaseHookHandle.java",
"chars": 2759,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/Hook.java",
"chars": 1718,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/HookFactory.java",
"chars": 8372,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/HookedMethodHandler.java",
"chars": 2815,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/BinderHook.java",
"chars": 4911,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IAppOpsServiceBinderHook.java",
"chars": 1806,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IAudioServiceBinderHook.java",
"chars": 1804,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IClipboardBinderHook.java",
"chars": 1790,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IContentServiceBinderHook.java",
"chars": 1821,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IDisplayManagerBinderHook.java",
"chars": 1650,
"preview": "package com.morgoo.droidplugin.hook.binder;\n\nimport android.content.Context;\nimport android.os.IBinder;\n\nimport com.morg"
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IGraphicsStatsBinderHook.java",
"chars": 1919,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IInputMethodManagerBinderHook.java",
"chars": 2481,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ILocationManagerBinderHook.java",
"chars": 1820,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IMediaRouterServiceBinderHook.java",
"chars": 1844,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IMmsBinderHook.java",
"chars": 1727,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IMountServiceBinderHook.java",
"chars": 1789,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/INotificationManagerBinderHook.java",
"chars": 1809,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IPhoneSubInfoBinderHook.java",
"chars": 1791,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ISearchManagerBinderHook.java",
"chars": 1851,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ISessionManagerBinderHook.java",
"chars": 1822,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ISmsBinderHook.java",
"chars": 1727,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ISubBinderHook.java",
"chars": 1798,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ITelephonyBinderHook.java",
"chars": 1783,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ITelephonyRegistryBinderHook.java",
"chars": 1825,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IWifiManagerBinderHook.java",
"chars": 2903,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/IWindowManagerBinderHook.java",
"chars": 3428,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/MyServiceManager.java",
"chars": 1964,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ServiceManagerBinderHook.java",
"chars": 4500,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/binder/ServiceManagerCacheBinderHook.java",
"chars": 7375,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IActivityManagerHookHandle.java",
"chars": 102268,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IAppOpsServiceHookHandle.java",
"chars": 5004,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IAudioServiceHookHandle.java",
"chars": 4904,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IClipboardHookHandle.java",
"chars": 4863,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IContentProviderInvokeHandle.java",
"chars": 7219,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IContentServiceHandle.java",
"chars": 3730,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IDisplayManagerHookHandle.java",
"chars": 1380,
"preview": "package com.morgoo.droidplugin.hook.handle;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport com."
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IGraphicsStatsHookHandle.java",
"chars": 2171,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IInputMethodManagerHookHandle.java",
"chars": 3141,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ILocationManagerHookHandle.java",
"chars": 3757,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IMediaRouterServiceHookHandle.java",
"chars": 2809,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IMmsHookHandle.java",
"chars": 4892,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IMountServiceHookHandle.java",
"chars": 5982,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/INotificationManagerHookHandle.java",
"chars": 28037,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IPackageManagerHookHandle.java",
"chars": 76584,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IPhoneSubInfoHookHandle.java",
"chars": 11686,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ISearchManagerHookHandle.java",
"chars": 2529,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ISessionManagerHookHandle.java",
"chars": 2114,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ISmsHookHandle.java",
"chars": 8311,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ISubBinderHookHandle.java",
"chars": 11532,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ITelephonyHookHandle.java",
"chars": 54680,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ITelephonyRegistryHookHandle.java",
"chars": 8143,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IWifiManagerHookHandle.java",
"chars": 8009,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IWindowManagerHookHandle.java",
"chars": 3171,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/IWindowSessionInvokeHandle.java",
"chars": 4457,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/LibCoreHookHandle.java",
"chars": 7102,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/PluginCallback.java",
"chars": 20787,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/PluginInstrumentation.java",
"chars": 12993,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/ReplaceCallingPackageHookedMethodHandler.java",
"chars": 1374,
"preview": "package com.morgoo.droidplugin.hook.handle;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.os."
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/handle/WebViewFactoryProviderHookHandle.java",
"chars": 4995,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/IActivityManagerHook.java",
"chars": 6048,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/IContentProviderHook.java",
"chars": 1964,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/IPackageManagerHook.java",
"chars": 3424,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/IWindowSessionHook.java",
"chars": 1644,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/InstrumentationHook.java",
"chars": 3347,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/LibCoreHook.java",
"chars": 3678,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/PluginCallbackHook.java",
"chars": 3363,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/ProxyHook.java",
"chars": 4093,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/proxy/WebViewFactoryProviderHook.java",
"chars": 2410,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/hook/xhook/SQLiteDatabaseHook.java",
"chars": 4201,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/IPluginManagerImpl.java",
"chars": 53027,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/PluginManager.java",
"chars": 38649,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/IntentMatcher.java",
"chars": 25306,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParser.java",
"chars": 5899,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi15.java",
"chars": 4853,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi16.java",
"chars": 5774,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi20.java",
"chars": 1907,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi21.java",
"chars": 12949,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi22.java",
"chars": 3187,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PackageParserApi22Preview1.java",
"chars": 2550,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/pm/parser/PluginPackageParser.java",
"chars": 22264,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/reflect/FieldUtils.java",
"chars": 9948,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/reflect/MemberUtils.java",
"chars": 9626,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/reflect/MethodUtils.java",
"chars": 13461,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/reflect/Utils.java",
"chars": 3132,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/reflect/Validate.java",
"chars": 1185,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/AbstractContentProviderStub.java",
"chars": 13211,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/AbstractServiceStub.java",
"chars": 5201,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/ActivityStub.java",
"chars": 21613,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/ContentProviderStub.java",
"chars": 1627,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/MyFakeIBinder.java",
"chars": 2097,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/ServcesManager.java",
"chars": 13852,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/ServiceStub.java",
"chars": 2128,
"preview": "/*\n** copyright (c) 2015 Andy Zhang(Zhangyong232@gmail.com)\n**\n** This file is part of DroidPlugin.\n**\n** DroidPlugin is"
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/droidplugin/stub/ShortcutProxyActivity.java",
"chars": 4497,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/AttributeCache.java",
"chars": 4453,
"preview": "/*\n**\n** Copyright 2007, The Android Open Source Project\n**\n** Licensed under the Apache License, Version 2.0 (the \"Lice"
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/ComponentNameComparator.java",
"chars": 1592,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/Log.java",
"chars": 7887,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/MyProxy.java",
"chars": 3183,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/Utils.java",
"chars": 5474,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ActivityManagerCompat.java",
"chars": 1072,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ActivityManagerNativeCompat.java",
"chars": 1532,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ActivityThreadCompat.java",
"chars": 3200,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/BuildCompat.java",
"chars": 2895,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/BundleCompat.java",
"chars": 1597,
"preview": "package com.morgoo.helper.compat;\n\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\n\nimport"
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/CompatibilityInfoCompat.java",
"chars": 1645,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ContentProviderCompat.java",
"chars": 2980,
"preview": "package com.morgoo.helper.compat;\n\nimport android.content.ContentProviderClient;\nimport android.content.Context;\nimport "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ContentProviderHolderCompat.java",
"chars": 1700,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IActivityManagerCompat.java",
"chars": 1537,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IAppOpsServiceCompat.java",
"chars": 1668,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IAudioServiceCompat.java",
"chars": 1642,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IClipboardCompat.java",
"chars": 1637,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IContentServiceCompat.java",
"chars": 1654,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IDisplayManagerCompat.java",
"chars": 859,
"preview": "package com.morgoo.helper.compat;\n\nimport android.os.IBinder;\n\nimport com.morgoo.droidplugin.reflect.MethodUtils;\n\nimpor"
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IGraphicsStatsCompat.java",
"chars": 1644,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IInputMethodManagerCompat.java",
"chars": 1684,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ILocationManagerCompat.java",
"chars": 1658,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IMediaRouterServiceCompat.java",
"chars": 1660,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IMmsCompat.java",
"chars": 1621,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IMountServiceCompat.java",
"chars": 1651,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/INotificationManagerCompat.java",
"chars": 1659,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IPackageDataObserverCompat.java",
"chars": 1468,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IPhoneSubInfoCompat.java",
"chars": 1674,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ISearchManagerCompat.java",
"chars": 1620,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ISessionManagerCompat.java",
"chars": 1662,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ISmsCompat.java",
"chars": 1621,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ISubCompat.java",
"chars": 1647,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ITelephonyCompat.java",
"chars": 1664,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ITelephonyRegistryCompat.java",
"chars": 1689,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IWifiManagerCompat.java",
"chars": 1644,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/IWindowManagerCompat.java",
"chars": 1644,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/NativeLibraryHelperCompat.java",
"chars": 6103,
"preview": "package com.morgoo.helper.compat;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\n\nimport com.morgoo.droi"
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/PackageManagerCompat.java",
"chars": 1445,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ParceledListSliceCompat.java",
"chars": 1547,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ProcessCompat.java",
"chars": 1599,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/QueuedWorkCompat.java",
"chars": 1495,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/ServiceManagerCompat.java",
"chars": 1587,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/SingletonCompat.java",
"chars": 1831,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/SystemPropertiesCompat.java",
"chars": 1830,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/UserHandleCompat.java",
"chars": 1383,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/VMRuntimeCompat.java",
"chars": 1829,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/compat/WebViewFactoryCompat.java",
"chars": 1645,
"preview": "/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyong232@gmail.com>\n**\n** This file is part of "
},
{
"path": "project/Libraries/DroidPlugin/src/main/java/com/morgoo/helper/utils/ProcessUtils.java",
"chars": 2880,
"preview": "package com.morgoo.helper.utils;\n\nimport android.app.ActivityManager;\nimport android.content.Context;\n\nimport java.lang."
},
{
"path": "project/Libraries/DroidPlugin/src/main/res/drawable-xxhdpi/plugin_activity_loading.xml",
"chars": 1020,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyo"
},
{
"path": "project/Libraries/DroidPlugin/src/main/res/values/strings.xml",
"chars": 1122,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyo"
},
{
"path": "project/Libraries/DroidPlugin/src/main/res/values/styles.xml",
"chars": 1238,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyo"
},
{
"path": "project/Libraries/DroidPlugin/src/main/res/values-v11/styles.xml",
"chars": 1257,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyo"
},
{
"path": "project/Libraries/DroidPlugin/src/main/res/values-v14/styles.xml",
"chars": 1276,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n/*\n** DroidPlugin Project\n**\n** Copyright(c) 2015 Andy Zhang <zhangyo"
},
{
"path": "project/Test/ApiTest/build.gradle",
"chars": 711,
"preview": "apply plugin: 'com.android.application'\n\ndependencies {\n implementation fileTree(include: '*.jar', dir: 'libs')\n i"
},
{
"path": "project/Test/ApiTest/proguard-project.txt",
"chars": 781,
"preview": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in t"
},
{
"path": "project/Test/ApiTest/project.properties",
"chars": 634,
"preview": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# T"
},
{
"path": "project/Test/ApiTest/src/main/AndroidManifest.xml",
"chars": 6472,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package="
},
{
"path": "project/Test/ApiTest/src/main/cpp/Core.cpp",
"chars": 994,
"preview": "#include <jni.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/cdefs.h>\n#include <dlfcn.h>\n\n#include \"help/nativ"
},
{
"path": "project/Test/ApiTest/src/main/cpp/HelperJni/HelperJni.cpp",
"chars": 816,
"preview": "/*\n * HelperJni.cpp\n *\n * Created on: 2014年5月28日\n * Author: zhangyong6\n */\n\n#include <errno.h>\n#include <stdlib.h>"
}
]
// ... and 70 more files (download for full content)
About this extraction
This page contains the full source code of the DroidPluginTeam/DroidPlugin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 270 files (1.6 MB), approximately 381.1k tokens, and a symbol index with 2197 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.