Repository: didi/VirtualAPK
Branch: master
Commit: b1a778a06688
Files: 211
Total size: 640.5 KB
Directory structure:
gitextract__l3v4sn5/
├── .gitignore
├── AndroidStub/
│ ├── README.md
│ ├── build.gradle
│ ├── gradle.properties
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── aidl/
│ │ └── android/
│ │ ├── app/
│ │ │ ├── IActivityManager.aidl
│ │ │ ├── IApplicationThread.aidl
│ │ │ ├── INotificationManager.aidl
│ │ │ └── IServiceConnection.aidl
│ │ └── content/
│ │ ├── IIntentReceiver.aidl
│ │ └── IIntentSender.aidl
│ └── java/
│ ├── android/
│ │ ├── app/
│ │ │ ├── ActivityManagerNative.java
│ │ │ ├── ActivityThread.java
│ │ │ ├── ApplicationThreadNative.java
│ │ │ ├── Instrumentation.java
│ │ │ ├── LoadedApk.java
│ │ │ └── ResourcesManager.java
│ │ ├── content/
│ │ │ ├── ContentResolver.java
│ │ │ ├── IContentProvider.java
│ │ │ ├── pm/
│ │ │ │ ├── ManifestDigest.java
│ │ │ │ ├── PackageParser.java
│ │ │ │ ├── PackageUserState.java
│ │ │ │ └── VerifierInfo.java
│ │ │ └── res/
│ │ │ ├── CompatibilityInfo.java
│ │ │ ├── Resources.java
│ │ │ ├── ResourcesImpl.java
│ │ │ └── ResourcesKey.java
│ │ ├── databinding/
│ │ │ ├── DataBinderMapper.java
│ │ │ └── DataBindingComponent.java
│ │ ├── os/
│ │ │ ├── ServiceManager.java
│ │ │ └── SystemProperties.java
│ │ └── util/
│ │ └── Singleton.java
│ └── com/
│ └── android/
│ └── internal/
│ └── R.java
├── CONTRIBUTING.md
├── CoreLibrary/
│ ├── .gitignore
│ ├── build.gradle
│ ├── gradle.properties
│ ├── proguard-rules.pro
│ ├── src/
│ │ ├── androidTest/
│ │ │ └── java/
│ │ │ └── com/
│ │ │ └── didi/
│ │ │ └── virtualapk/
│ │ │ └── core/
│ │ │ └── ApplicationTest.java
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java/
│ │ │ │ ├── android/
│ │ │ │ │ ├── content/
│ │ │ │ │ │ └── ContentResolverWrapper.java
│ │ │ │ │ └── databinding/
│ │ │ │ │ └── DataBinderMapperProxy.java
│ │ │ │ └── com/
│ │ │ │ └── didi/
│ │ │ │ └── virtualapk/
│ │ │ │ ├── PluginManager.java
│ │ │ │ ├── delegate/
│ │ │ │ │ ├── ActivityManagerProxy.java
│ │ │ │ │ ├── IContentProviderProxy.java
│ │ │ │ │ ├── LocalService.java
│ │ │ │ │ ├── RemoteContentProvider.java
│ │ │ │ │ ├── RemoteService.java
│ │ │ │ │ └── StubActivity.java
│ │ │ │ ├── internal/
│ │ │ │ │ ├── ActivityLifecycleCallbacksProxy.java
│ │ │ │ │ ├── ComponentsHandler.java
│ │ │ │ │ ├── Constants.java
│ │ │ │ │ ├── LoadedPlugin.java
│ │ │ │ │ ├── PluginContentResolver.java
│ │ │ │ │ ├── PluginContext.java
│ │ │ │ │ ├── ResourcesManager.java
│ │ │ │ │ ├── StubActivityInfo.java
│ │ │ │ │ ├── VAInstrumentation.java
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── DexUtil.java
│ │ │ │ │ ├── PackageParserCompat.java
│ │ │ │ │ ├── PluginUtil.java
│ │ │ │ │ └── Settings.java
│ │ │ │ └── utils/
│ │ │ │ ├── Reflector.java
│ │ │ │ ├── RunUtil.java
│ │ │ │ └── ZipVerifyUtil.java
│ │ │ └── res/
│ │ │ └── values/
│ │ │ └── strings.xml
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── didi/
│ │ └── virtualapk/
│ │ └── core/
│ │ └── ExampleUnitTest.java
│ └── upload.gradle
├── LICENSE
├── PluginDemo/
│ ├── app/
│ │ ├── build.gradle
│ │ ├── gradle.properties
│ │ ├── proguard-rules.pro
│ │ └── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── aidl/
│ │ │ └── com/
│ │ │ └── didi/
│ │ │ └── virtualapk/
│ │ │ └── demo/
│ │ │ ├── aidl/
│ │ │ │ ├── Book.aidl
│ │ │ │ ├── IBookManager.aidl
│ │ │ │ └── IOnNewBookArrivedListener.aidl
│ │ │ ├── binderpool/
│ │ │ │ ├── IBinderPool.aidl
│ │ │ │ ├── ICompute.aidl
│ │ │ │ └── ISecurityCenter.aidl
│ │ │ └── manualbinder/
│ │ │ └── Book.aidl
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── didi/
│ │ │ └── virtualapk/
│ │ │ └── demo/
│ │ │ ├── MainActivity.java
│ │ │ ├── MyApplication.java
│ │ │ ├── SecondActivity.java
│ │ │ ├── ThirdActivity.java
│ │ │ ├── aidl/
│ │ │ │ ├── Book.java
│ │ │ │ ├── BookManagerActivity.java
│ │ │ │ └── BookManagerService.java
│ │ │ ├── binderpool/
│ │ │ │ ├── BinderPool.java
│ │ │ │ ├── BinderPoolActivity.java
│ │ │ │ ├── BinderPoolService.java
│ │ │ │ ├── ComputeImpl.java
│ │ │ │ └── SecurityCenterImpl.java
│ │ │ ├── manager/
│ │ │ │ ├── BookManager.java
│ │ │ │ └── UserManager.java
│ │ │ ├── manualbinder/
│ │ │ │ ├── Book.java
│ │ │ │ ├── BookManagerImpl.java
│ │ │ │ └── IBookManager.java
│ │ │ ├── messenger/
│ │ │ │ ├── MessengerActivity.java
│ │ │ │ └── MessengerService.java
│ │ │ ├── model/
│ │ │ │ └── User.java
│ │ │ ├── provider/
│ │ │ │ ├── BookProvider.java
│ │ │ │ ├── DbOpenHelper.java
│ │ │ │ └── ProviderActivity.java
│ │ │ ├── socket/
│ │ │ │ ├── TCPClientActivity.java
│ │ │ │ └── TCPServerService.java
│ │ │ └── utils/
│ │ │ ├── MyConstants.java
│ │ │ └── MyUtils.java
│ │ └── res/
│ │ ├── drawable/
│ │ │ └── edit.xml
│ │ ├── layout/
│ │ │ ├── activity_binder_pool.xml
│ │ │ ├── activity_book_manager.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_messenger.xml
│ │ │ ├── activity_provider.xml
│ │ │ ├── activity_second.xml
│ │ │ ├── activity_tcpclient.xml
│ │ │ └── activity_third.xml
│ │ └── values/
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── make.sh
│ └── settings.gradle
├── README.md
├── RELEASE-NOTES.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── didi/
│ │ └── virtualapk/
│ │ └── ApplicationTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── didi/
│ │ │ └── virtualapk/
│ │ │ ├── MainActivity.java
│ │ │ └── VAApplication.java
│ │ └── res/
│ │ ├── layout/
│ │ │ └── activity_main.xml
│ │ ├── values/
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── values-en/
│ │ │ └── strings.xml
│ │ └── values-w820dp/
│ │ └── dimens.xml
│ └── test/
│ └── java/
│ └── com/
│ └── didi/
│ └── virtualapk/
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── keystore/
│ ├── test.cer
│ └── test.keystore
├── settings.gradle
└── virtualapk-gradle-plugin/
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── src/
│ └── main/
│ ├── groovy/
│ │ └── com.didi.virtualapk/
│ │ ├── BasePlugin.groovy
│ │ ├── Constants.groovy
│ │ ├── VAExtention.groovy
│ │ ├── VAHostPlugin.groovy
│ │ ├── VAPlugin.groovy
│ │ ├── aapt/
│ │ │ ├── AXmlEditor.groovy
│ │ │ ├── Aapt.groovy
│ │ │ ├── ArscEditor.groovy
│ │ │ ├── AssetEditor.groovy
│ │ │ ├── CppHexEditor.groovy
│ │ │ ├── ResAttr.groovy
│ │ │ ├── ResStringFlag.groovy
│ │ │ ├── ResStringPoolSpan.groovy
│ │ │ ├── ResTableEntry.groovy
│ │ │ ├── ResTableType.groovy
│ │ │ ├── ResType.groovy
│ │ │ ├── ResValueDataType.groovy
│ │ │ ├── SymbolParser.groovy
│ │ │ └── packageinfo
│ │ ├── collector/
│ │ │ ├── HostClassAndResCollector.groovy
│ │ │ ├── HostJniLibsCollector.groovy
│ │ │ ├── ResourceCollector.groovy
│ │ │ ├── dependence/
│ │ │ │ ├── AarDependenceInfo.groovy
│ │ │ │ ├── DependenceInfo.groovy
│ │ │ │ └── JarDependenceInfo.groovy
│ │ │ └── res/
│ │ │ ├── ResourceEntry.groovy
│ │ │ └── StyleableEntry.groovy
│ │ ├── hooker/
│ │ │ ├── DxTaskHooker.groovy
│ │ │ ├── GradleTaskHooker.groovy
│ │ │ ├── MergeAssetsHooker.groovy
│ │ │ ├── MergeJniLibsHooker.groovy
│ │ │ ├── MergeManifestsHooker.groovy
│ │ │ ├── PrepareDependenciesHooker.groovy
│ │ │ ├── ProcessResourcesHooker.groovy
│ │ │ ├── ProguardHooker.groovy
│ │ │ ├── ShrinkResourcesHooker.groovy
│ │ │ └── TaskHookerManager.groovy
│ │ ├── tasks/
│ │ │ └── AssemblePlugin.groovy
│ │ ├── transform/
│ │ │ ├── StripClassAndResTransform.groovy
│ │ │ └── TransformWrapper.groovy
│ │ └── utils/
│ │ ├── CheckList.groovy
│ │ ├── FileBinaryCategory.groovy
│ │ ├── FileUtil.groovy
│ │ ├── PackagingUtils.java
│ │ ├── Reflect.java
│ │ └── ZipUtil.groovy
│ ├── java/
│ │ └── com/
│ │ └── didi/
│ │ └── virtualapk/
│ │ ├── databinding/
│ │ │ └── annotationprocessor/
│ │ │ └── ProcessDataBinding.java
│ │ └── utils/
│ │ └── Log.java
│ └── resources/
│ └── META-INF/
│ ├── gradle-plugins/
│ │ ├── com.didi.virtualapk.host.properties
│ │ └── com.didi.virtualapk.plugin.properties
│ └── services/
│ └── javax.annotation.processing.Processor
└── upload.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Generated by MacOSX
.DS_Store
# Generated by VIM
.*.swp
# Generated by IntelliJ
.idea/
*.iml
/*/*.iml
/*/*/*.iml
# PluginDemo
PluginDemo/.idea/
PluginDemo/.gradle/
PluginDemo/build/
PluginDemo/*.iml
PluginDemo/local.properties
PluginDemo/host/
# Generated by Gradle
.gradle
build/
# Generated by Eclipse
.metadata
.settings
.project
.classpath
# Files generated by Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
local.properties
buildSrc
================================================
FILE: AndroidStub/README.md
================================================
# Android Framework Stub
该库主要是针对在 app 中无法直接调用 Android Framework 中很多隐藏的 API 而创造的一系列 stub 类用来欺骗编译器,从而避免了使用反射去调用造成性能损失
================================================
FILE: AndroidStub/build.gradle
================================================
group = 'com.didichuxing.foundation'
version = '0.0.5'
apply plugin: 'com.android.library'
android {
compileSdkVersion VERSION_COMPILE_SDK
buildToolsVersion VERSION_BUILD_TOOLS
defaultConfig {
minSdkVersion VERSION_MIN_SDK
targetSdkVersion VERSION_TARGET_SDK
versionCode 1
versionName "1.0"
}
compileOptions {
sourceCompatibility SOURCE_COMPATIBILITY
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
android.libraryVariants.all { variant ->
def jarTask = project.tasks.create("jar${variant.name.capitalize()}", Jar)
jarTask.excludes = [
'android/BuildConfig.class',
'android/R.class'
]
jarTask.dependsOn variant.javaCompile
jarTask.from variant.javaCompile.destinationDir
artifacts.add('archives', jarTask)
}
apply plugin: 'maven'
uploadArchives {
repositories {
mavenDeployer {
pom.project {
groupId project.group
artifactId 'android-framework'
version project.version
description project.description ?: ''
packaging 'jar'
}
repository(url: MAVEN_RELEASES_REPOSITORY_URL) {
authentication(userName: MAVEN_USERNAME, password: MAVEN_PASSWORD)
}
snapshotRepository(url: MAVEN_SNAPSHOTS_REPOSITORY_URL) {
authentication(userName: MAVEN_USERNAME, password: MAVEN_PASSWORD)
}
}
}
}
dependencies {
api 'com.android.support:support-annotations:22.2.0'
api 'com.android.databinding:library:1.3.1'
api 'com.android.databinding:baseLibrary:3.0.0'
}
================================================
FILE: AndroidStub/gradle.properties
================================================
MAVEN_RELEASES_REPOSITORY_URL=
MAVEN_SNAPSHOTS_REPOSITORY_URL=
MAVEN_USERNAME=test
MAVEN_PASSWORD=test
================================================
FILE: AndroidStub/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/johnson/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: AndroidStub/src/main/AndroidManifest.xml
================================================
================================================
FILE: AndroidStub/src/main/aidl/android/app/IActivityManager.aidl
================================================
package android.app;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IIntentSender;
import android.os.IBinder;
import android.os.IInterface;
/**
* @author johnsonlee
*/
interface IActivityManager {
ComponentName startService(in IApplicationThread caller, in Intent service, in String resolvedType, in String callingPackage, in int userId);
int stopService(in IApplicationThread caller, in Intent service, in String resolvedType, in int userId);
boolean stopServiceToken(in ComponentName className, in IBinder token, in int startId);
void setServiceForeground(in ComponentName className, in IBinder token, in int id, in Notification notification, in boolean keepNotification);
int bindService(in IApplicationThread caller, in IBinder token, in Intent service, in String resolvedType, in IServiceConnection connection, in int flags, in String callingPackage, in int userId);
boolean unbindService(in IServiceConnection connection);
void publishService(in IBinder token, in Intent intent, in IBinder service);
void unbindFinished(in IBinder token, in Intent service, in boolean doRebind);
IIntentSender getIntentSender(in int type, in String packageName, in IBinder token, in String resultWho, int requestCode, in Intent[] intents, in String[] resolvedTypes, in int flags, in Bundle options, in int userId);
void cancelIntentSender(in IIntentSender sender);
String getPackageForIntentSender(in IIntentSender sender);
int getUidForIntentSender(in IIntentSender sender);
}
================================================
FILE: AndroidStub/src/main/aidl/android/app/IApplicationThread.aidl
================================================
package android.app;
interface IApplicationThread {
}
================================================
FILE: AndroidStub/src/main/aidl/android/app/INotificationManager.aidl
================================================
/*
* Copyright 2007, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
import android.app.Notification;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
interface INotificationManager
{
void cancelAllNotifications(String pkg, int userId);
void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, in Notification notification, inout int[] idReceived, int userId);
void cancelNotificationWithTag(String pkg, String tag, int id, int userId);
void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled);
boolean areNotificationsEnabledForPackage(String pkg, int uid);
boolean areNotificationsEnabled(String pkg);
}
================================================
FILE: AndroidStub/src/main/aidl/android/app/IServiceConnection.aidl
================================================
/* //device/java/android/android/app/IServiceConnection.aidl
**
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
package android.app;
import android.content.ComponentName;
/** @hide */
oneway interface IServiceConnection {
// void connected(in ComponentName name, IBinder service);
/** Added in Android O */
void connected(in ComponentName name, IBinder service, boolean dead);
}
================================================
FILE: AndroidStub/src/main/aidl/android/content/IIntentReceiver.aidl
================================================
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content;
import android.content.Intent;
import android.os.Bundle;
/**
* 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.
*/
oneway interface IIntentReceiver {
void performReceive(in Intent intent, int resultCode, String data, in Bundle extras, boolean ordered, boolean sticky, int sendingUser);
}
================================================
FILE: AndroidStub/src/main/aidl/android/content/IIntentSender.aidl
================================================
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.os.Bundle;
oneway interface IIntentSender {
void send(int code, in Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, in Bundle options);
}
================================================
FILE: AndroidStub/src/main/java/android/app/ActivityManagerNative.java
================================================
package android.app;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
/**
* @author johnsonlee
*/
public abstract class ActivityManagerNative extends Binder implements IActivityManager {
public static IActivityManager getDefault() {
throw new RuntimeException("Stub!");
}
public static boolean isSystemReady() {
throw new RuntimeException("Stub!");
}
public static void broadcastStickyIntent(final Intent intent, final String permission, final int userId) {
throw new RuntimeException("Stub!");
}
static public IActivityManager asInterface(IBinder obj) {
throw new RuntimeException("Stub!");
}
public ActivityManagerNative() {
throw new RuntimeException("Stub!");
}
}
================================================
FILE: AndroidStub/src/main/java/android/app/ActivityThread.java
================================================
package android.app;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
/**
* @author johnsonlee
*/
public final class ActivityThread {
public static ActivityThread currentActivityThread() {
throw new RuntimeException("Stub!");
}
public static boolean isSystem() {
throw new RuntimeException("Stub!");
}
public static String currentOpPackageName() {
throw new RuntimeException("Stub!");
}
public static String currentPackageName() {
throw new RuntimeException("Stub!");
}
public static String currentProcessName() {
throw new RuntimeException("Stub!");
}
public static Application currentApplication() {
throw new RuntimeException("Stub!");
}
public ApplicationThread getApplicationThread() {
throw new RuntimeException("Stub!");
}
public Instrumentation getInstrumentation() {
throw new RuntimeException("Stub!");
}
public Looper getLooper() {
throw new RuntimeException("Stub!");
}
public Application getApplication() {
throw new RuntimeException("Stub!");
}
public String getProcessName() {
throw new RuntimeException("Stub!");
}
public final ActivityInfo resolveActivityInfo(final Intent intent) {
throw new RuntimeException("Stub!");
}
public final Activity getActivity(final IBinder token) {
throw new RuntimeException("Stub!");
}
final Handler getHandler() {
throw new RuntimeException("Stub!");
}
private class ApplicationThread extends ApplicationThreadNative {
}
}
================================================
FILE: AndroidStub/src/main/java/android/app/ApplicationThreadNative.java
================================================
package android.app;
import android.os.Binder;
import android.os.IBinder;
/**
* @author johnsonlee
*/
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread {
@Override
public IBinder asBinder() {
throw new RuntimeException("Stub!");
}
}
================================================
FILE: AndroidStub/src/main/java/android/app/Instrumentation.java
================================================
package android.app;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PersistableBundle;
/**
* Created by qiaopu on 2018/5/7.
*/
public class Instrumentation {
public Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
throw new RuntimeException("Stub!");
}
public void callApplicationOnCreate(Application app) {
throw new RuntimeException("Stub!");
}
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
throw new RuntimeException("Stub!");
}
public void callActivityOnCreate(Activity activity, Bundle icicle) {
throw new RuntimeException("Stub!");
}
public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) {
throw new RuntimeException("Stub!");
}
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) {
throw new RuntimeException("Stub!");
}
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
throw new RuntimeException("Stub!");
}
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Fragment target, Intent intent, int requestCode, Bundle options) {
throw new RuntimeException("Stub!");
}
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, String target, Intent intent, int requestCode, Bundle options) {
throw new RuntimeException("Stub!");
}
public Context getContext() {
throw new RuntimeException("Stub!");
}
public Context getTargetContext() {
throw new RuntimeException("Stub!");
}
public ComponentName getComponentName() {
throw new RuntimeException("Stub!");
}
public static final class ActivityResult {
public ActivityResult(int resultCode, Intent resultData) {
throw new RuntimeException("Stub!");
}
}
}
================================================
FILE: AndroidStub/src/main/java/android/app/LoadedApk.java
================================================
package android.app;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.pm.ApplicationInfo;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Handler;
import java.io.File;
/**
* Created by johnson on 24/8/16.
*/
public final class LoadedApk {
public String getPackageName() {
throw new RuntimeException("Stub!");
}
public ApplicationInfo getApplicationInfo() {
throw new RuntimeException("Stub!");
}
public ClassLoader getClassLoader() {
throw new RuntimeException("Stub!");
}
public String getAppDir() {
throw new RuntimeException("Stub!");
}
public String getLibDir() {
throw new RuntimeException("Stub!");
}
public String getResDir() {
throw new RuntimeException("Stub!");
}
public String[] getSplitAppDirs() {
throw new RuntimeException("Stub!");
}
public String[] getSplitResDirs() {
throw new RuntimeException("Stub!");
}
public String[] getOverlayDirs() {
throw new RuntimeException("Stub!");
}
public String getDataDir() {
throw new RuntimeException("Stub!");
}
public File getDataDirFile() {
throw new RuntimeException("Stub!");
}
public AssetManager getAssets(final ActivityThread mainThread) {
throw new RuntimeException("Stub!");
}
public Resources getResources(final ActivityThread mainThread) {
throw new RuntimeException("Stub!");
}
public IIntentReceiver getReceiverDispatcher(final BroadcastReceiver r, final Context context, final Handler handler, final Instrumentation instrumentation, final boolean registered) {
throw new RuntimeException("Stub!");
}
public IIntentReceiver forgetReceiverDispatcher(final Context context, final BroadcastReceiver r) {
throw new RuntimeException("Stub!");
}
}
================================================
FILE: AndroidStub/src/main/java/android/app/ResourcesManager.java
================================================
package android.app;
/**
* Created by qiaopu on 2018/4/25.
*/
public class ResourcesManager {
public static ResourcesManager getInstance() {
throw new RuntimeException("Stub!");
}
public void appendLibAssetForMainAssetPath(String assetPath, String libAsset) {
throw new RuntimeException("Stub!");
}
}
================================================
FILE: AndroidStub/src/main/java/android/content/ContentResolver.java
================================================
package android.content;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/**
* Created by qiaopu on 2018/5/7.
*/
public abstract class ContentResolver {
public ContentResolver(Context context) {
throw new RuntimeException("Stub!");
}
public final @Nullable
Bundle call(@NonNull Uri uri, @NonNull String method,
@Nullable String arg, @Nullable Bundle extras) {
throw new RuntimeException("Stub!");
}
protected abstract IContentProvider acquireProvider(Context c, String name);
protected IContentProvider acquireExistingProvider(Context c, String name) {
throw new RuntimeException("Stub!");
}
public abstract boolean releaseProvider(IContentProvider icp);
protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
public abstract boolean releaseUnstableProvider(IContentProvider icp);
public abstract void unstableProviderDied(IContentProvider icp);
public void appNotRespondingViaProvider(IContentProvider icp) {
throw new RuntimeException("Stub!");
}
}
================================================
FILE: AndroidStub/src/main/java/android/content/IContentProvider.java
================================================
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content;
import android.os.IInterface;
/**
* The ipc interface to talk to a content provider.
* @hide
*/
public interface IContentProvider extends IInterface {
}
================================================
FILE: AndroidStub/src/main/java/android/content/pm/ManifestDigest.java
================================================
package android.content.pm;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.jar.Attributes;
/**
* @author johnsonlee
*/
public class ManifestDigest implements Parcelable {
ManifestDigest(final byte[] digest) {
throw new RuntimeException("Stub!");
}
private ManifestDigest(final Parcel source) {
throw new RuntimeException("Stub!");
}
static ManifestDigest fromAttributes(final Attributes attributes) {
throw new RuntimeException("Stub!");
}
@Override
public int describeContents() {
throw new RuntimeException("Stub!");
}
@Override
public boolean equals(Object o) {
throw new RuntimeException("Stub!");
}
@Override
public int hashCode() {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
throw new RuntimeException("Stub!");
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public ManifestDigest createFromParcel(Parcel source) {
return new ManifestDigest(source);
}
public ManifestDigest[] newArray(int size) {
return new ManifestDigest[size];
}
};
}
================================================
FILE: AndroidStub/src/main/java/android/content/pm/PackageParser.java
================================================
package android.content.pm;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import java.io.File;
import java.io.PrintWriter;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @author johnsonlee
*/
public class PackageParser {
public final static int PARSE_IS_SYSTEM = 1 << 0;
public final static int PARSE_CHATTY = 1 << 1;
public final static int PARSE_MUST_BE_APK = 1 << 2;
public final static int PARSE_IGNORE_PROCESSES = 1 << 3;
public final static int PARSE_FORWARD_LOCK = 1 << 4;
public final static int PARSE_EXTERNAL_STORAGE = 1 << 5;
public final static int PARSE_IS_SYSTEM_DIR = 1 << 6;
public final static int PARSE_IS_PRIVILEGED = 1 << 7;
public final static int PARSE_COLLECT_CERTIFICATES = 1 << 8;
public final static int PARSE_TRUSTED_OVERLAY = 1 << 9;
public static class NewPermissionInfo {
public final String name;
public final int sdkVersion;
public final int fileVersion;
public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {
throw new RuntimeException("Stub!");
}
}
public static class SplitPermissionInfo {
public final String rootPerm;
public final String[] newPerms;
public final int targetSdk;
public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
throw new RuntimeException("Stub!");
}
}
public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] = new PackageParser.NewPermissionInfo[]{
new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.os.Build.VERSION_CODES.DONUT, 0),
new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE, android.os.Build.VERSION_CODES.DONUT, 0)
};
static class ParsePackageItemArgs {
final Package owner;
final String[] outError;
final int nameRes;
final int labelRes;
final int iconRes;
final int logoRes;
final int bannerRes;
String tag;
TypedArray sa;
ParsePackageItemArgs(final Package owner, final String[] outError, final int nameRes, final int labelRes, final int iconRes, final int logoRes, final int bannerRes) { throw new RuntimeException("Stub!");
}
}
static class ParseComponentArgs extends ParsePackageItemArgs {
final String[] sepProcesses;
final int processRes;
final int descriptionRes;
final int enabledRes;
int flags;
ParseComponentArgs(final Package owner, final String[] outError, final int nameRes, final int labelRes, final int iconRes, final int logoRes, final int bannerRes, final String[] sepProcesses, final int processRes, final int descriptionRes, final int enabledRes) {
super(owner, outError, nameRes, labelRes, iconRes, logoRes, bannerRes);
throw new RuntimeException("Stub!");
}
}
public static class PackageLite {
public final String packageName;
public final int versionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
/** Names of any split APKs, ordered by parsed splitName */
public final String[] splitNames;
/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
* path to the cluster directory.
*/
public final String codePath;
/** Path of base APK */
public final String baseCodePath;
/** Paths of any split APKs, ordered by parsed splitName */
public final String[] splitCodePaths;
/** Revision code of base APK */
public final int baseRevisionCode;
/** Revision codes of any split APKs, ordered by parsed splitName */
public final int[] splitRevisionCodes;
public final boolean coreApp;
public final boolean multiArch;
public final boolean extractNativeLibs;
public PackageLite(final String codePath, final ApkLite baseApk, final String[] splitNames, final String[] splitCodePaths, final int[] splitRevisionCodes) {
throw new RuntimeException("Stub!");
}
public List getAllCodePaths() {
throw new RuntimeException("Stub!");
}
}
public static class ApkLite {
public final String codePath;
public final String packageName;
public final String splitName;
public final int versionCode;
public final int revisionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
public final Signature[] signatures;
public final boolean coreApp;
public final boolean multiArch;
public final boolean extractNativeLibs;
public ApkLite(final String codePath, final String packageName, final String splitName, final int versionCode, final int revisionCode, final int installLocation, final List verifiers, final Signature[] signatures, final boolean coreApp, final boolean multiArch, final boolean extractNativeLibs) {
throw new RuntimeException("Stub!");
}
}
/**
* For Android 5.0+
*/
public PackageParser() {
throw new RuntimeException("Stub!");
}
public PackageParser(final String archiveSourcePath) {
throw new RuntimeException("Stub!");
}
public void setSeparateProcesses(final String[] procs) {
throw new RuntimeException("Stub!");
}
public void setOnlyCoreApps(final boolean onlyCoreApps) {
throw new RuntimeException("Stub!");
}
public void setDisplayMetrics(final DisplayMetrics metrics) {
throw new RuntimeException("Stub!");
}
public static final boolean isApkFile(final File file) {
throw new RuntimeException("Stub!");
}
public static PackageInfo generatePackageInfo(final PackageParser.Package p, final int gids[], final int flags, final long firstInstallTime, final long lastUpdateTime, final Set grantedPermissions, final PackageUserState state) {
throw new RuntimeException("Stub!");
}
public static boolean isAvailable(final PackageUserState state) {
throw new RuntimeException("Stub!");
}
public static PackageInfo generatePackageInfo(final PackageParser.Package p, final int gids[], final int flags, final long firstInstallTime, final long lastUpdateTime, final Set grantedPermissions, final PackageUserState state, final int userId) {
throw new RuntimeException("Stub!");
}
/**
* Parse only lightweight details about the package at the given location.
* Automatically detects if the package is a monolithic style (single APK
* file) or cluster style (directory of APKs).
*
* This performs sanity checking on cluster style packages, such as
* requiring identical package name and version codes, a single base APK,
* and unique split names.
*
* @see PackageParser#parsePackage(File, int)
*/
public static PackageLite parsePackageLite(final File packageFile, final int flags) throws PackageParserException {
throw new RuntimeException("Stub!");
}
/**
* Parse the package at the given location. Automatically detects if the
* package is a monolithic style (single APK file) or cluster style
* (directory of APKs).
*
* This performs sanity checking on cluster style packages, such as
* requiring identical package name and version codes, a single base APK,
* and unique split names.
*
* Note that this does not perform signature verification; that
* must be done separately in {@link #collectCertificates(Package, int)}.
*
* @see #parsePackageLite(File, int)
* @since Android 5.0+
*/
public Package parsePackage(final File packageFile, final int flags) throws PackageParserException {
throw new RuntimeException("Stub!");
}
/**
*
* @param sourceFile
* @param destCodePath
* @param metrics
* @param flags
* @return
* @since Android 2.3+
*/
public Package parsePackage(final File sourceFile, final String destCodePath, final DisplayMetrics metrics, final int flags) {
throw new RuntimeException("Stub!");
}
public void collectManifestDigest(final Package pkg) throws PackageParserException {
throw new RuntimeException("Stub!");
}
public void collectCertificates(final Package pkg, final int flags) throws PackageParserException {
throw new RuntimeException("Stub!");
}
/**
* Utility method that retrieves lightweight details about a single APK
* file, including package name, split name, and install location.
*
* @param apkFile path to a single APK
* @param flags optional parse flags, such as
* {@link #PARSE_COLLECT_CERTIFICATES}
*/
public static ApkLite parseApkLite(final File apkFile, final int flags) throws PackageParserException {
throw new RuntimeException("Stub!");
}
public static ApplicationInfo generateApplicationInfo(final Package p, final int flags, final PackageUserState state) {
throw new RuntimeException("Stub!");
}
public static ApplicationInfo generateApplicationInfo(final Package p, final int flags, final PackageUserState state, final int userId) {
throw new RuntimeException("Stub!");
}
public static ApplicationInfo generateApplicationInfo(final ApplicationInfo ai, final int flags, final PackageUserState state, final int userId) {
throw new RuntimeException("Stub!");
}
public static final PermissionInfo generatePermissionInfo(final Permission p, final int flags) {
throw new RuntimeException("Stub!");
}
public static final PermissionGroupInfo generatePermissionGroupInfo(final PermissionGroup pg, final int flags) {
throw new RuntimeException("Stub!");
}
public static final InstrumentationInfo generateInstrumentationInfo(final Instrumentation i, final int flags) {
throw new RuntimeException("Stub!");
}
public static final ServiceInfo generateServiceInfo(final Service s, final int flags, final PackageUserState state, final int userId) {
throw new RuntimeException("Stub!");
}
public static final ProviderInfo generateProviderInfo(final Provider p, final int flags, final PackageUserState state, final int userId) {
throw new RuntimeException("Stub!");
}
public static final ActivityInfo generateActivityInfo(final Activity a, final int flags, final PackageUserState state, final int userId) {
throw new RuntimeException("Stub!");
}
public static final ActivityInfo generateActivityInfo(final ActivityInfo ai, final int flags, final PackageUserState state, final int userId) {
throw new RuntimeException("Stub!");
}
/**
* 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.
*/
public final static class Package {
public String packageName;
/** Names of any split APKs, ordered by parsed splitName */
public String[] splitNames;
// TODO: work towards making these paths invariant
public String volumeUuid;
/**
* Path where this package was found on disk. For monolithic packages
* this is path to single base APK file; for cluster packages this is
* path to the cluster directory.
*/
public String codePath;
/** Path of base APK */
public String baseCodePath;
/** Paths of any split APKs, ordered by parsed splitName */
public String[] splitCodePaths;
/** Revision code of base APK */
public int baseRevisionCode;
/** Revision codes of any split APKs, ordered by parsed splitName */
public int[] splitRevisionCodes;
/** Flags of any split APKs; ordered by parsed splitName */
public int[] splitFlags;
/**
* Private flags of any split APKs; ordered by parsed splitName.
*
* {@hide}
*/
public int[] splitPrivateFlags;
public boolean baseHardwareAccelerated;
// For now we only support one application per package.
public final ApplicationInfo applicationInfo = new ApplicationInfo();
public final ArrayList permissions = new ArrayList(0);
public final ArrayList permissionGroups = new ArrayList(0);
public final ArrayList activities = new ArrayList(0);
public final ArrayList receivers = new ArrayList(0);
public final ArrayList providers = new ArrayList(0);
public final ArrayList services = new ArrayList(0);
public final ArrayList instrumentation = new ArrayList(0);
public final ArrayList requestedPermissions = new ArrayList();
public ArrayList protectedBroadcasts;
public ArrayList libraryNames = null;
public ArrayList usesLibraries = null;
public ArrayList usesOptionalLibraries = null;
public String[] usesLibraryFiles = null;
public ArrayList preferredActivityFilters = null;
public ArrayList mOriginalPackages = null;
public String mRealPackage = null;
public ArrayList mAdoptPermissions = null;
// We store the application meta-data independently to avoid multiple unwanted references
public Bundle mAppMetaData = null;
// The version code declared for this package.
public int mVersionCode;
// The version name declared for this package.
public String mVersionName;
// The shared user id that this package wants to use.
public String mSharedUserId;
// The shared user label that this package wants to use.
public int mSharedUserLabel;
// Signatures that were read from the package.
public Signature[] mSignatures;
public SigningDetails mSigningDetails;
public Certificate[][] mCertificates;
// For use by package manager service for quick lookup of
// preferred up order.
public int mPreferredOrder = 0;
// For use by package manager to keep track of where it needs to do dexopt.
// public final ArraySet mDexOptPerformed = new ArraySet<>(4);
// For use by package manager to keep track of when a package was last used.
public long mLastPackageUsageTimeInMills;
// // User set enabled state.
// public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
//
// // Whether the package has been stopped.
// public boolean mSetStopped = false;
// Additional data supplied by callers.
public Object mExtras;
// Applications hardware preferences
public ArrayList configPreferences = null;
// Applications requested features
public ArrayList reqFeatures = null;
// Applications requested feature groups
public ArrayList featureGroups = null;
public int installLocation;
public boolean coreApp;
/* An app that's required for all users and cannot be uninstalled for a user */
public boolean mRequiredForAllUsers;
/* The restricted account authenticator type that is used by this application */
public String mRestrictedAccountType;
/* The required account type without which this application will not function */
public String mRequiredAccountType;
/**
* Digest suitable for comparing whether this package's manifest is the
* same as another.
*/
public ManifestDigest manifestDigest;
public String mOverlayTarget;
public int mOverlayPriority;
public boolean mTrustedOverlay;
/**
* Data used to feed the KeySetManagerService
*/
public ArraySet mSigningKeys;
public ArraySet mUpgradeKeySets;
public ArrayMap> mKeySetMapping;
/**
* The install time abi override for this package, if any.
*
* TODO: This seems like a horrible place to put the abiOverride because
* this isn't something the packageParser parsers. However, this fits in with
* the rest of the PackageManager where package scanning randomly pushes
* and prods fields out of {@code this.applicationInfo}.
*/
public String cpuAbiOverride;
public Package(String packageName) {
throw new RuntimeException("Stub!");
}
public List getAllCodePaths() {
throw new RuntimeException("Stub!");
}
/**
* Filtered set of {@link #getAllCodePaths()} that excludes
* resource-only APKs.
*/
public List getAllCodePathsExcludingResourceOnly() {
throw new RuntimeException("Stub!");
}
public void setPackageName(final String newName) {
throw new RuntimeException("Stub!");
}
public boolean hasComponentClassName(final String name) {
throw new RuntimeException("Stub!");
}
public boolean isForwardLocked() {
throw new RuntimeException("Stub!");
}
public boolean isSystemApp() {
throw new RuntimeException("Stub!");
}
public boolean isPrivilegedApp() {
throw new RuntimeException("Stub!");
}
public boolean isUpdatedSystemApp() {
throw new RuntimeException("Stub!");
}
public boolean canHaveOatDir() {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
}
public static class Component {
public final Package owner;
public final ArrayList intents;
public final String className;
public Bundle metaData;
ComponentName componentName;
String componentShortName;
public Component(final Package owner) {
throw new RuntimeException("Stub!");
}
public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
throw new RuntimeException("Stub!");
}
public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
throw new RuntimeException("Stub!");
}
public Component(final Component clone) {
throw new RuntimeException("Stub!");
}
public ComponentName getComponentName() {
throw new RuntimeException("Stub!");
}
public void appendComponentShortName(final StringBuilder sb) {
throw new RuntimeException("Stub!");
}
public void printComponentShortName(final PrintWriter pw) {
throw new RuntimeException("Stub!");
}
public void setPackageName(final String packageName) {
throw new RuntimeException("Stub!");
}
}
public final static class Permission extends Component {
public final PermissionInfo info;
public boolean tree;
public PermissionGroup group;
public Permission(final Package owner) {
super(owner);
throw new RuntimeException("Stub!");
}
public Permission(final Package owner, final PermissionInfo info) {
super(owner);
throw new RuntimeException("Stub!");
}
@Override
public void setPackageName(final String packageName) {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
}
public final static class PermissionGroup extends Component {
public final PermissionGroupInfo info;
public PermissionGroup(final Package owner) {
super(owner);
throw new RuntimeException("Stub!");
}
public PermissionGroup(final Package owner, final PermissionGroupInfo info) {
super(owner);
throw new RuntimeException("Stub!");
}
@Override
public void setPackageName(final String packageName) {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
}
public final static class Activity extends Component {
public final ActivityInfo info;
public Activity(final ParseComponentArgs args, final ActivityInfo info) {
super(args, info);
throw new RuntimeException("Stub!");
}
@Override
public void setPackageName(final String packageName) {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
}
public final static class Service extends Component {
public final ServiceInfo info;
public Service(final ParseComponentArgs args, final ServiceInfo info) {
super(args, info);
throw new RuntimeException("Stub!");
}
@Override
public void setPackageName(final String packageName) {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
}
public final static class Provider extends Component {
public final ProviderInfo info;
public boolean syncable;
public Provider(final ParseComponentArgs args, final ProviderInfo info) {
super(args, info);
throw new RuntimeException("Stub!");
}
public Provider(final Provider existingProvider) {
super(existingProvider);
throw new RuntimeException("Stub!");
}
@Override
public void setPackageName(final String packageName) {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
}
public final static class Instrumentation extends Component {
public final InstrumentationInfo info;
public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo info) {
super(args, info);
throw new RuntimeException("Stub!");
}
@Override
public void setPackageName(final String packageName) {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
}
@SuppressLint("ParcelCreator")
public static class IntentInfo extends IntentFilter {
public boolean hasDefault;
public int labelRes;
public CharSequence nonLocalizedLabel;
public int icon;
public int logo;
public int banner;
public int preferred;
}
@SuppressLint("ParcelCreator")
public final static class ActivityIntentInfo extends IntentInfo {
public final Activity activity;
public ActivityIntentInfo(final Activity activity) {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
}
@SuppressLint("ParcelCreator")
public final static class ServiceIntentInfo extends IntentInfo {
public final Service service;
public ServiceIntentInfo(final Service service) {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
}
@SuppressLint("ParcelCreator")
public static final class ProviderIntentInfo extends IntentInfo {
public final Provider provider;
public ProviderIntentInfo(final Provider provider) {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
}
public static class PackageParserException extends Exception {
public PackageParserException(int error, String detailMessage) {
super(detailMessage);
throw new RuntimeException("Stub!");
}
public PackageParserException(int error, String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
throw new RuntimeException("Stub!");
}
}
public static class SigningDetails {
public Signature[] signatures;
}
}
================================================
FILE: AndroidStub/src/main/java/android/content/pm/PackageUserState.java
================================================
package android.content.pm;
import android.util.ArraySet;
/**
* @author johnsonlee
*/
public class PackageUserState {
public boolean stopped;
public boolean notLaunched;
public boolean installed;
public boolean hidden; // Is the app restricted by owner / admin
public int enabled;
public boolean blockUninstall;
public String lastDisableAppCaller;
public ArraySet disabledComponents;
public ArraySet enabledComponents;
public int domainVerificationStatus;
public int appLinkGeneration;
public PackageUserState() {
throw new RuntimeException("Stub!");
}
public PackageUserState(final PackageUserState o) {
throw new RuntimeException("Stub!");
}
}
================================================
FILE: AndroidStub/src/main/java/android/content/pm/VerifierInfo.java
================================================
package android.content.pm;
import android.os.Parcel;
import android.os.Parcelable;
import java.security.PublicKey;
/**
* @author johnsonlee
*/
public class VerifierInfo implements Parcelable{
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public VerifierInfo createFromParcel(final Parcel source) {
return new VerifierInfo(source);
}
public VerifierInfo[] newArray(final int size) {
return new VerifierInfo[size];
}
};
public VerifierInfo(final String packageName, final PublicKey publicKey) {
throw new RuntimeException("Stub!");
}
private VerifierInfo(final Parcel source) {
throw new RuntimeException("Stub!");
}
@Override
public int describeContents() {
throw new RuntimeException("Stub!");
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
throw new RuntimeException("Stub!");
}
}
================================================
FILE: AndroidStub/src/main/java/android/content/res/CompatibilityInfo.java
================================================
package android.content.res;
import android.content.pm.ApplicationInfo;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by qiaopu on 2018/5/3.
*/
public class CompatibilityInfo implements Parcelable {
public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw,
boolean forceCompat) {
throw new RuntimeException("Stub!");
}
@Override
public int describeContents() {
throw new RuntimeException("Stub!");
}
@Override
public void writeToParcel(Parcel dest, int flags) {
throw new RuntimeException("Stub!");
}
public static final Parcelable.Creator CREATOR
= new Parcelable.Creator() {
@Override
public CompatibilityInfo createFromParcel(Parcel source) {
throw new RuntimeException("Stub!");
}
@Override
public CompatibilityInfo[] newArray(int size) {
throw new RuntimeException("Stub!");
}
};
}
================================================
FILE: AndroidStub/src/main/java/android/content/res/Resources.java
================================================
package android.content.res;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
/**
* Created by qiaopu on 2018/5/18.
*/
public class Resources {
public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
throw new RuntimeException("Stub!");
}
public final AssetManager getAssets() {
throw new RuntimeException("Stub!");
}
public int getColor(int id) throws NotFoundException {
throw new RuntimeException("Stub!");
}
public Configuration getConfiguration() {
throw new RuntimeException("Stub!");
}
public DisplayMetrics getDisplayMetrics() {
throw new RuntimeException("Stub!");
}
public Drawable getDrawable(int id) throws NotFoundException {
throw new RuntimeException("Stub!");
}
public String getString(int id) throws NotFoundException {
throw new RuntimeException("Stub!");
}
public CharSequence getText(int id) throws NotFoundException {
throw new RuntimeException("Stub!");
}
public XmlResourceParser getXml(int id) throws NotFoundException {
throw new RuntimeException("Stub!");
}
public ResourcesImpl getImpl() {
throw new RuntimeException("Stub!");
}
public final Theme newTheme() {
throw new RuntimeException("Stub!");
}
public void updateConfiguration(Configuration config, DisplayMetrics metrics) {
throw new RuntimeException("Stub!");
}
public final class Theme {
public void applyStyle(int resId, boolean force) {
throw new RuntimeException("Stub!");
}
public TypedArray obtainStyledAttributes(int[] attrs) {
throw new RuntimeException("Stub!");
}
public void setTo(Theme other) {
throw new RuntimeException("Stub!");
}
}
public static class NotFoundException extends RuntimeException {
}
}
================================================
FILE: AndroidStub/src/main/java/android/content/res/ResourcesImpl.java
================================================
package android.content.res;
/**
* Created by qiaopu on 2018/5/18.
*/
public class ResourcesImpl {
}
================================================
FILE: AndroidStub/src/main/java/android/content/res/ResourcesKey.java
================================================
package android.content.res;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/**
* Created by qiaopu on 2018/5/3.
*/
public final class ResourcesKey {
@Nullable
public final String mResDir;
@Nullable
public final String[] mSplitResDirs;
@Nullable
public final String[] mOverlayDirs;
@Nullable
public final String[] mLibDirs;
public final int mDisplayId;
@NonNull
public final Configuration mOverrideConfiguration;
@NonNull
public final CompatibilityInfo mCompatInfo;
public ResourcesKey(@Nullable String resDir,
@Nullable String[] splitResDirs,
@Nullable String[] overlayDirs,
@Nullable String[] libDirs,
int displayId,
@Nullable Configuration overrideConfig,
@Nullable CompatibilityInfo compatInfo) {
throw new RuntimeException("Stub!");
}
}
================================================
FILE: AndroidStub/src/main/java/android/databinding/DataBinderMapper.java
================================================
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.databinding;
import android.view.View;
/**
* This class will be stripped from the jar and then replaced by the annotation processor
* as part of the code generation step. This class's existence is just to ensure that
* compile works and no reflection is needed to access the generated class.
*/
class DataBinderMapper {
public ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view,
int layoutId) {
return null;
}
ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View[] view, int layoutId) {
return null;
}
public int getLayoutId(String tag) { return 0; }
public String convertBrIdToString(int id) {
return null;
}
public static int TARGET_MIN_SDK = 0;
}
================================================
FILE: AndroidStub/src/main/java/android/databinding/DataBindingComponent.java
================================================
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.databinding;
/**
* This interface is generated during compilation to contain getters for all used instance
* BindingAdapters. When a BindingAdapter is an instance method, an instance of the class
* implementing the method must be instantiated. This interface will be generated with a getter
* for each class with the name get* where * is simple class name of the declaring BindingAdapter
* class/interface. Name collisions will be resolved by adding a numeric suffix to the getter.
*
* An instance of this class may also be passed into static or instance BindingAdapters as the
* first parameter.
*
* If you are using Dagger 2, you should extend this interface and annotate the extended interface
* as a Component.
*/
public interface DataBindingComponent {
}
================================================
FILE: AndroidStub/src/main/java/android/os/ServiceManager.java
================================================
package android.os;
import java.util.HashMap;
import java.util.Map;
/**
* @author johnsonlee
*/
public final class ServiceManager {
private static HashMap sCache = new HashMap();
public static IBinder getService(final String name) {
throw new RuntimeException("Stub!");
}
public static void addService(final String name, final IBinder service) {
throw new RuntimeException("Stub!");
}
public static void addService(final String name, final IBinder service, final boolean allowIsolated) {
throw new RuntimeException("Stub!");
}
public static IBinder checkService(final String name) {
throw new RuntimeException("Stub!");
}
public static String[] listServices() throws RemoteException {
throw new RuntimeException("Stub!");
}
public static void initServiceCache(final Map cache) {
throw new RuntimeException("Stub!");
}
}
================================================
FILE: AndroidStub/src/main/java/android/os/SystemProperties.java
================================================
package android.os;
/**
* @author johnsonlee
*/
public class SystemProperties {
public static String get(final String key) {
throw new RuntimeException("Stub!");
}
public static String get(final String key, final String def) {
throw new RuntimeException("Stub!");
}
public static int getInt(final String key, final int def) {
throw new RuntimeException("Stub!");
}
public static long getLong(final String key, final long def) {
throw new RuntimeException("Stub!");
}
public static boolean getBoolean(final String key, final boolean def) {
throw new RuntimeException("Stub!");
}
public static void set(final String key, final String val) {
throw new RuntimeException("Stub!");
}
public static void addChangeCallback(final Runnable callback) {
throw new RuntimeException("Stub!");
}
}
================================================
FILE: AndroidStub/src/main/java/android/util/Singleton.java
================================================
package android.util;
/**
* @author johnsonlee
*/
public abstract class Singleton {
public Singleton() {
throw new RuntimeException("Stub!");
}
protected abstract T create();
public T get() {
throw new RuntimeException("Stub!");
}
}
================================================
FILE: AndroidStub/src/main/java/com/android/internal/R.java
================================================
package com.android.internal;
/**
* @author johnsonlee
*/
public final class R {
public static final class id {
public static int action0 = 0;
public static int actions = 0;
public static int action_divider = 0;
public static int big_picture = 0;
public static int big_text = 0;
public static int big_text2 = 0;
public static int chronometer = 0;
public static int icon = 0;
public static int inbox_text0 = 0;
public static int inbox_text1 = 0;
public static int inbox_text2 = 0;
public static int inbox_text3 = 0;
public static int inbox_text4 = 0;
public static int inbox_text5 = 0;
public static int inbox_text6 = 0;
public static int inbox_end_pad = 0;
public static int info = 0;
public static int line1 = 0;
public static int line3 = 0;
public static int overflow_divider = 0;
public static int progress = 0;
public static int title = 0;
public static int text = 0;
public static int text2 = 0;
public static int time = 0;
public static int right_icon = 0;
public static int fillInIntent = 0;
public static int status_bar_latest_event_content = 0;
}
}
================================================
FILE: CONTRIBUTING.md
================================================
# Contribution Guideline
Thanks for considering to contribute this project. All issues and pull requests are highly appreciated.
## Pull Requests
Before sending pull request to this project, please read and follow guidelines below.
1. Branch: We only accept pull request on `dev` branch.
2. Coding style: Follow the coding style used in VirtualAPK.
3. Commit message: Use English and be aware of your spell.
4. Test: Make sure to test your code.
Add device mode, API version, related log, screenshots and other related information in your pull request if possible.
NOTE: We assume all your contribution can be licensed under the [Apache License 2.0](https://github.com/didi/VirtualAPK/blob/master/LICENSE).
## Issues
We love clearly described issues. :)
Following information can help us to resolve the issue faster.
* Device mode and hardware information.
* API version.
* Logs.
* Screenshots.
* Steps to reproduce the issue.
================================================
FILE: CoreLibrary/.gitignore
================================================
/build
================================================
FILE: CoreLibrary/build.gradle
================================================
import com.android.build.gradle.api.ApplicationVariant
import com.android.build.gradle.api.LibraryVariant
import com.google.common.base.Joiner
apply plugin: 'com.android.library'
android {
compileSdkVersion VERSION_COMPILE_SDK
buildToolsVersion VERSION_BUILD_TOOLS
defaultConfig {
minSdkVersion VERSION_MIN_SDK
targetSdkVersion VERSION_TARGET_SDK
versionCode 1
versionName "1.0.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility SOURCE_COMPATIBILITY
}
lintOptions {
abortOnError false
}
}
repositories {
mavenCentral()
jcenter()
}
final String projectAndroidStub = ':AndroidStub'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
provided project(projectAndroidStub)
testCompile 'junit:junit:4.12'
}
// Using Stub classes first when compiling.
afterEvaluate {
project.android.libraryVariants.each { LibraryVariant variant ->
variant.javaCompile.doFirst { JavaCompile javaCompile ->
String projectAndroidStubPath = project.project(projectAndroidStub).projectDir.canonicalPath
// println "projectAndroidStubPath: ${projectAndroidStubPath}"
File stubPath = javaCompile.classpath.find {
it.canonicalPath.startsWith(projectAndroidStubPath)
}
if (stubPath == null) {
throw new RuntimeException("reset bootclasspath error.")
}
javaCompile.options.setBootClasspath(Joiner.on(File.pathSeparator).join(stubPath, javaCompile.options.bootClasspath))
}
}
}
apply from: 'upload.gradle'
================================================
FILE: CoreLibrary/gradle.properties
================================================
================================================
FILE: CoreLibrary/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/didi/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: CoreLibrary/src/androidTest/java/com/didi/virtualapk/core/ApplicationTest.java
================================================
package com.didi.virtualapk.core;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* Testing Fundamentals
*/
public class ApplicationTest extends ApplicationTestCase {
public ApplicationTest() {
super(Application.class);
}
}
================================================
FILE: CoreLibrary/src/main/AndroidManifest.xml
================================================
================================================
FILE: CoreLibrary/src/main/java/android/content/ContentResolverWrapper.java
================================================
package android.content;
import android.annotation.TargetApi;
import android.os.Build;
/**
* Wrapper of {@link ContentResolver}
* Created by qiaopu on 2018/5/7.
*/
public abstract class ContentResolverWrapper extends ContentResolver {
ContentResolver mBase;
public ContentResolverWrapper(Context context) {
super(context);
mBase = context.getContentResolver();
}
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
return mBase.acquireProvider(context, auth);
}
@Override
protected IContentProvider acquireExistingProvider(Context context, String auth) {
return mBase.acquireExistingProvider(context, auth);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
protected IContentProvider acquireUnstableProvider(Context context, String auth) {
return mBase.acquireUnstableProvider(context, auth);
}
@Override
public boolean releaseProvider(IContentProvider icp) {
return mBase.releaseProvider(icp);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public boolean releaseUnstableProvider(IContentProvider icp) {
return mBase.releaseUnstableProvider(icp);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void unstableProviderDied(IContentProvider icp) {
mBase.unstableProviderDied(icp);
}
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public void appNotRespondingViaProvider(IContentProvider icp) {
// dark greylist in Android P
// mBase.appNotRespondingViaProvider(icp);
}
}
================================================
FILE: CoreLibrary/src/main/java/android/databinding/DataBinderMapperProxy.java
================================================
package android.databinding;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.View;
import com.didi.virtualapk.PluginManager;
import com.didi.virtualapk.internal.Constants;
import com.didi.virtualapk.internal.LoadedPlugin;
import java.util.LinkedList;
/**
* Replace {@link DataBindingUtil#sMapper}.
* Created by qiaopu on 2018/4/11.
*/
public class DataBinderMapperProxy extends DataBinderMapper implements PluginManager.Callback {
public static final String TAG = Constants.TAG_PREFIX + "DataBinderMapperProxy";
private final LinkedList mMappers;
private DataBinderMapper[] mCache;
public DataBinderMapperProxy(@NonNull Object source) {
mMappers = new LinkedList<>();
addMapper((DataBinderMapper) source);
}
@Override
public ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view, int layoutId) {
ViewDataBinding viewDataBinding;
for (DataBinderMapper mapper : getCache()) {
viewDataBinding = mapper.getDataBinder(bindingComponent, view, layoutId);
if (viewDataBinding != null) {
// Log.d(TAG, "Found by mapper: " + mapper);
return viewDataBinding;
}
}
return null;
}
@Override
ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View[] view, int layoutId) {
ViewDataBinding viewDataBinding;
for (DataBinderMapper mapper : getCache()) {
viewDataBinding = mapper.getDataBinder(bindingComponent, view, layoutId);
if (viewDataBinding != null) {
// Log.d(TAG, "Found by mapper: " + mapper);
return viewDataBinding;
}
}
return null;
}
@Override
public int getLayoutId(String tag) {
int layoutId;
for (DataBinderMapper mapper : getCache()) {
layoutId = mapper.getLayoutId(tag);
if (layoutId != 0) {
// Log.d(TAG, "Found by mapper: " + mapper);
return layoutId;
}
}
return 0;
}
@Override
public String convertBrIdToString(int id) {
String brId;
for (DataBinderMapper mapper : getCache()) {
brId = mapper.convertBrIdToString(id);
if (brId != null) {
// Log.d(TAG, "Found by mapper: " + mapper);
return brId;
}
}
return null;
}
@Override
public void onAddedLoadedPlugin(LoadedPlugin plugin) {
try {
String clsName = "android.databinding.DataBinderMapper_" + plugin.getPackageName().replace('.', '_');
Log.d(TAG, "Try to find the class: " + clsName);
Class cls = Class.forName(clsName, true, plugin.getClassLoader());
Object obj = cls.newInstance();
addMapper((DataBinderMapper) obj);
} catch (Exception e) {
Log.w(TAG, e);
}
}
private void addMapper(DataBinderMapper mapper) {
int size = 0;
synchronized (mMappers) {
mMappers.add(mapper);
mCache = null;
size = mMappers.size();
}
Log.d(TAG, "Added mapper: " + mapper + ", size: " + size);
}
private DataBinderMapper[] getCache() {
synchronized (mMappers) {
if (mCache == null) {
mCache = mMappers.toArray(new DataBinderMapper[mMappers.size()]);
}
return mCache;
}
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/PluginManager.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.Application;
import android.app.IActivityManager;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.util.Singleton;
import com.didi.virtualapk.delegate.ActivityManagerProxy;
import com.didi.virtualapk.delegate.IContentProviderProxy;
import com.didi.virtualapk.delegate.RemoteContentProvider;
import com.didi.virtualapk.internal.ComponentsHandler;
import com.didi.virtualapk.internal.Constants;
import com.didi.virtualapk.internal.LoadedPlugin;
import com.didi.virtualapk.internal.VAInstrumentation;
import com.didi.virtualapk.internal.utils.PluginUtil;
import com.didi.virtualapk.utils.Reflector;
import com.didi.virtualapk.utils.RunUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by renyugang on 16/8/9.
*/
public class PluginManager {
public static final String TAG = Constants.TAG_PREFIX + "PluginManager";
private static volatile PluginManager sInstance = null;
// Context of host app
protected final Context mContext;
protected final Application mApplication;
protected ComponentsHandler mComponentsHandler;
protected final Map mPlugins = new ConcurrentHashMap<>();
protected final List mCallbacks = new ArrayList<>();
protected VAInstrumentation mInstrumentation; // Hooked instrumentation
protected IActivityManager mActivityManager; // Hooked IActivityManager binder
protected IContentProvider mIContentProvider; // Hooked IContentProvider binder
public static PluginManager getInstance(Context base) {
if (sInstance == null) {
synchronized (PluginManager.class) {
if (sInstance == null) {
sInstance = createInstance(base);
}
}
}
return sInstance;
}
private static PluginManager createInstance(Context context) {
try {
Bundle metaData = context.getPackageManager()
.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA)
.metaData;
if (metaData == null) {
return new PluginManager(context);
}
String factoryClass = metaData.getString("VA_FACTORY");
if (factoryClass == null) {
return new PluginManager(context);
}
PluginManager pluginManager = Reflector.on(factoryClass).method("create", Context.class).call(context);
if (pluginManager != null) {
Log.d(TAG, "Created a instance of " + pluginManager.getClass());
return pluginManager;
}
} catch (Exception e) {
Log.w(TAG, "Created the instance error!", e);
}
return new PluginManager(context);
}
protected PluginManager(Context context) {
if (context instanceof Application) {
this.mApplication = (Application) context;
this.mContext = mApplication.getBaseContext();
} else {
final Context app = context.getApplicationContext();
if (app == null) {
this.mContext = context;
this.mApplication = ActivityThread.currentApplication();
} else {
this.mApplication = (Application) app;
this.mContext = mApplication.getBaseContext();
}
}
mComponentsHandler = createComponentsHandler();
hookCurrentProcess();
}
protected void hookCurrentProcess() {
hookInstrumentationAndHandler();
hookSystemServices();
hookDataBindingUtil();
}
public void init() {
RunUtil.getThreadPool().execute(new Runnable() {
@Override
public void run() {
doInWorkThread();
}
});
}
protected void doInWorkThread() {
}
public Application getHostApplication() {
return this.mApplication;
}
protected ComponentsHandler createComponentsHandler() {
return new ComponentsHandler(this);
}
protected VAInstrumentation createInstrumentation(Instrumentation origin) throws Exception {
return new VAInstrumentation(this, origin);
}
protected ActivityManagerProxy createActivityManagerProxy(IActivityManager origin) throws Exception {
return new ActivityManagerProxy(this, origin);
}
protected LoadedPlugin createLoadedPlugin(File apk) throws Exception {
return new LoadedPlugin(this, this.mContext, apk);
}
protected void hookDataBindingUtil() {
Reflector.QuietReflector reflector = Reflector.QuietReflector.on("android.databinding.DataBindingUtil").field("sMapper");
Object old = reflector.get();
if (old != null) {
try {
Callback callback = Reflector.on("android.databinding.DataBinderMapperProxy").constructor().newInstance();
reflector.set(callback);
addCallback(callback);
Log.d(TAG, "hookDataBindingUtil succeed : " + callback);
} catch (Reflector.ReflectedException e) {
Log.w(TAG, e);
}
}
}
public void addCallback(Callback callback) {
if (callback == null) {
return;
}
synchronized (mCallbacks) {
if (mCallbacks.contains(callback)) {
throw new RuntimeException("Already added " + callback + "!");
}
mCallbacks.add(callback);
}
}
public void removeCallback(Callback callback) {
synchronized (mCallbacks) {
mCallbacks.remove(callback);
}
}
/**
* hookSystemServices, but need to compatible with Android O in future.
*/
protected void hookSystemServices() {
try {
Singleton defaultSingleton;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
defaultSingleton = Reflector.on(ActivityManager.class).field("IActivityManagerSingleton").get();
} else {
defaultSingleton = Reflector.on(ActivityManagerNative.class).field("gDefault").get();
}
IActivityManager origin = defaultSingleton.get();
IActivityManager activityManagerProxy = (IActivityManager) Proxy.newProxyInstance(mContext.getClassLoader(), new Class[] { IActivityManager.class },
createActivityManagerProxy(origin));
// Hook IActivityManager from ActivityManagerNative
Reflector.with(defaultSingleton).field("mInstance").set(activityManagerProxy);
if (defaultSingleton.get() == activityManagerProxy) {
this.mActivityManager = activityManagerProxy;
Log.d(TAG, "hookSystemServices succeed : " + mActivityManager);
}
} catch (Exception e) {
Log.w(TAG, e);
}
}
protected void hookInstrumentationAndHandler() {
try {
ActivityThread activityThread = ActivityThread.currentActivityThread();
Instrumentation baseInstrumentation = activityThread.getInstrumentation();
// if (baseInstrumentation.getClass().getName().contains("lbe")) {
// // reject executing in paralell space, for example, lbe.
// System.exit(0);
// }
final VAInstrumentation instrumentation = createInstrumentation(baseInstrumentation);
Reflector.with(activityThread).field("mInstrumentation").set(instrumentation);
Handler mainHandler = Reflector.with(activityThread).method("getHandler").call();
Reflector.with(mainHandler).field("mCallback").set(instrumentation);
this.mInstrumentation = instrumentation;
Log.d(TAG, "hookInstrumentationAndHandler succeed : " + mInstrumentation);
} catch (Exception e) {
Log.w(TAG, e);
}
}
protected void hookIContentProviderAsNeeded() {
Uri uri = Uri.parse(RemoteContentProvider.getUri(mContext));
mContext.getContentResolver().call(uri, "wakeup", null, null);
try {
Field authority = null;
Field provider = null;
ActivityThread activityThread = ActivityThread.currentActivityThread();
Map providerMap = Reflector.with(activityThread).field("mProviderMap").get();
Iterator iter = providerMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
String auth;
if (key instanceof String) {
auth = (String) key;
} else {
if (authority == null) {
authority = key.getClass().getDeclaredField("authority");
authority.setAccessible(true);
}
auth = (String) authority.get(key);
}
if (auth.equals(RemoteContentProvider.getAuthority(mContext))) {
if (provider == null) {
provider = val.getClass().getDeclaredField("mProvider");
provider.setAccessible(true);
}
IContentProvider rawProvider = (IContentProvider) provider.get(val);
IContentProvider proxy = IContentProviderProxy.newInstance(mContext, rawProvider);
mIContentProvider = proxy;
Log.d(TAG, "hookIContentProvider succeed : " + mIContentProvider);
break;
}
}
} catch (Exception e) {
Log.w(TAG, e);
}
}
/**
* load a plugin into memory, then invoke it's Application.
* @param apk the file of plugin, should end with .apk
* @throws Exception
*/
public void loadPlugin(File apk) throws Exception {
if (null == apk) {
throw new IllegalArgumentException("error : apk is null.");
}
if (!apk.exists()) {
// throw the FileNotFoundException by opening a stream.
InputStream in = new FileInputStream(apk);
in.close();
}
LoadedPlugin plugin = createLoadedPlugin(apk);
if (null == plugin) {
throw new RuntimeException("Can't load plugin which is invalid: " + apk.getAbsolutePath());
}
this.mPlugins.put(plugin.getPackageName(), plugin);
synchronized (mCallbacks) {
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onAddedLoadedPlugin(plugin);
}
}
}
public LoadedPlugin getLoadedPlugin(Intent intent) {
return getLoadedPlugin(PluginUtil.getComponent(intent));
}
public LoadedPlugin getLoadedPlugin(ComponentName component) {
if (component == null) {
return null;
}
return this.getLoadedPlugin(component.getPackageName());
}
public LoadedPlugin getLoadedPlugin(String packageName) {
return this.mPlugins.get(packageName);
}
public List getAllLoadedPlugins() {
List list = new ArrayList<>();
list.addAll(mPlugins.values());
return list;
}
public Context getHostContext() {
return this.mContext;
}
public VAInstrumentation getInstrumentation() {
return this.mInstrumentation;
}
public IActivityManager getActivityManager() {
return this.mActivityManager;
}
public synchronized IContentProvider getIContentProvider() {
if (mIContentProvider == null) {
hookIContentProviderAsNeeded();
}
return mIContentProvider;
}
public ComponentsHandler getComponentsHandler() {
return mComponentsHandler;
}
public ResolveInfo resolveActivity(Intent intent) {
return this.resolveActivity(intent, 0);
}
public ResolveInfo resolveActivity(Intent intent, int flags) {
for (LoadedPlugin plugin : this.mPlugins.values()) {
ResolveInfo resolveInfo = plugin.resolveActivity(intent, flags);
if (null != resolveInfo) {
return resolveInfo;
}
}
return null;
}
public ResolveInfo resolveService(Intent intent, int flags) {
for (LoadedPlugin plugin : this.mPlugins.values()) {
ResolveInfo resolveInfo = plugin.resolveService(intent, flags);
if (null != resolveInfo) {
return resolveInfo;
}
}
return null;
}
public ProviderInfo resolveContentProvider(String name, int flags) {
for (LoadedPlugin plugin : this.mPlugins.values()) {
ProviderInfo providerInfo = plugin.resolveContentProvider(name, flags);
if (null != providerInfo) {
return providerInfo;
}
}
return null;
}
/**
* used in PluginPackageManager, do not invoke it from outside.
*/
@Deprecated
public List queryIntentActivities(Intent intent, int flags) {
List resolveInfos = new ArrayList();
for (LoadedPlugin plugin : this.mPlugins.values()) {
List result = plugin.queryIntentActivities(intent, flags);
if (null != result && result.size() > 0) {
resolveInfos.addAll(result);
}
}
return resolveInfos;
}
/**
* used in PluginPackageManager, do not invoke it from outside.
*/
@Deprecated
public List queryIntentServices(Intent intent, int flags) {
List resolveInfos = new ArrayList();
for (LoadedPlugin plugin : this.mPlugins.values()) {
List result = plugin.queryIntentServices(intent, flags);
if (null != result && result.size() > 0) {
resolveInfos.addAll(result);
}
}
return resolveInfos;
}
/**
* used in PluginPackageManager, do not invoke it from outside.
*/
@Deprecated
public List queryBroadcastReceivers(Intent intent, int flags) {
List resolveInfos = new ArrayList();
for (LoadedPlugin plugin : this.mPlugins.values()) {
List result = plugin.queryBroadcastReceivers(intent, flags);
if (null != result && result.size() > 0) {
resolveInfos.addAll(result);
}
}
return resolveInfos;
}
public interface Callback {
void onAddedLoadedPlugin(LoadedPlugin plugin);
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/delegate/ActivityManagerProxy.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk.delegate;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import com.didi.virtualapk.PluginManager;
import com.didi.virtualapk.internal.Constants;
import com.didi.virtualapk.internal.utils.PluginUtil;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author johnsonlee
*/
public class ActivityManagerProxy implements InvocationHandler {
private static final String TAG = Constants.TAG_PREFIX + "IActivityManagerProxy";
public static final int INTENT_SENDER_BROADCAST = 1;
public static final int INTENT_SENDER_ACTIVITY = 2;
public static final int INTENT_SENDER_ACTIVITY_RESULT = 3;
public static final int INTENT_SENDER_SERVICE = 4;
private PluginManager mPluginManager;
private IActivityManager mActivityManager;
public ActivityManagerProxy(PluginManager pluginManager, IActivityManager activityManager) {
this.mPluginManager = pluginManager;
this.mActivityManager = activityManager;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("startService".equals(method.getName())) {
try {
return startService(proxy, method, args);
} catch (Throwable e) {
Log.e(TAG, "Start service error", e);
}
} else if ("stopService".equals(method.getName())) {
try {
return stopService(proxy, method, args);
} catch (Throwable e) {
Log.e(TAG, "Stop Service error", e);
}
} else if ("stopServiceToken".equals(method.getName())) {
try {
return stopServiceToken(proxy, method, args);
} catch (Throwable e) {
Log.e(TAG, "Stop service token error", e);
}
} else if ("bindService".equals(method.getName())) {
try {
return bindService(proxy, method, args);
} catch (Throwable e) {
Log.w(TAG, e);
}
} else if ("unbindService".equals(method.getName())) {
try {
return unbindService(proxy, method, args);
} catch (Throwable e) {
Log.w(TAG, e);
}
} else if ("getIntentSender".equals(method.getName())) {
try {
getIntentSender(method, args);
} catch (Exception e) {
Log.w(TAG, e);
}
} else if ("overridePendingTransition".equals(method.getName())){
try {
overridePendingTransition(method, args);
} catch (Exception e){
Log.w(TAG, e);
}
}
try {
// sometimes system binder has problems.
return method.invoke(this.mActivityManager, args);
} catch (Throwable th) {
Throwable c = th.getCause();
if (c != null && c instanceof DeadObjectException) {
// retry connect to system binder
IBinder ams = ServiceManager.getService(Context.ACTIVITY_SERVICE);
if (ams != null) {
IActivityManager am = ActivityManagerNative.asInterface(ams);
mActivityManager = am;
}
}
Throwable cause = th;
do {
if (cause instanceof RemoteException) {
throw cause;
}
} while ((cause = cause.getCause()) != null);
throw c != null ? c : th;
}
}
protected Object startService(Object proxy, Method method, Object[] args) throws Throwable {
IApplicationThread appThread = (IApplicationThread) args[0];
Intent target = (Intent) args[1];
ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
if (null == resolveInfo || null == resolveInfo.serviceInfo) {
// is host service
return method.invoke(this.mActivityManager, args);
}
return startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_START_SERVICE);
}
protected Object stopService(Object proxy, Method method, Object[] args) throws Throwable {
Intent target = (Intent) args[1];
ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
if (null == resolveInfo || null == resolveInfo.serviceInfo) {
// is hot service
return method.invoke(this.mActivityManager, args);
}
startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_STOP_SERVICE);
return 1;
}
protected Object stopServiceToken(Object proxy, Method method, Object[] args) throws Throwable {
ComponentName component = (ComponentName) args[0];
Intent target = new Intent().setComponent(component);
ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
if (null == resolveInfo || null == resolveInfo.serviceInfo) {
// is hot service
return method.invoke(this.mActivityManager, args);
}
startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_STOP_SERVICE);
return true;
}
protected Object bindService(Object proxy, Method method, Object[] args) throws Throwable {
Intent target = (Intent) args[2];
ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
if (null == resolveInfo || null == resolveInfo.serviceInfo) {
// is host service
return method.invoke(this.mActivityManager, args);
}
Bundle bundle = new Bundle();
PluginUtil.putBinder(bundle, "sc", (IBinder) args[4]);
startDelegateServiceForTarget(target, resolveInfo.serviceInfo, bundle, RemoteService.EXTRA_COMMAND_BIND_SERVICE);
mPluginManager.getComponentsHandler().remberIServiceConnection((IBinder) args[4], target);
return 1;
}
protected Object unbindService(Object proxy, Method method, Object[] args) throws Throwable {
IBinder iServiceConnection = (IBinder)args[0];
Intent target = mPluginManager.getComponentsHandler().forgetIServiceConnection(iServiceConnection);
if (target == null) {
// is host service
return method.invoke(this.mActivityManager, args);
}
ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_UNBIND_SERVICE);
return true;
}
protected ComponentName startDelegateServiceForTarget(Intent target, ServiceInfo serviceInfo, Bundle extras, int command) {
Intent wrapperIntent = wrapperTargetIntent(target, serviceInfo, extras, command);
return mPluginManager.getHostContext().startService(wrapperIntent);
}
protected Intent wrapperTargetIntent(Intent target, ServiceInfo serviceInfo, Bundle extras, int command) {
// fill in service with ComponentName
target.setComponent(new ComponentName(serviceInfo.packageName, serviceInfo.name));
String pluginLocation = mPluginManager.getLoadedPlugin(target.getComponent()).getLocation();
// start delegate service to run plugin service inside
boolean local = PluginUtil.isLocalService(serviceInfo);
Class extends Service> delegate = local ? LocalService.class : RemoteService.class;
Intent intent = new Intent();
intent.setClass(mPluginManager.getHostContext(), delegate);
intent.putExtra(RemoteService.EXTRA_TARGET, target);
intent.putExtra(RemoteService.EXTRA_COMMAND, command);
intent.putExtra(RemoteService.EXTRA_PLUGIN_LOCATION, pluginLocation);
if (extras != null) {
intent.putExtras(extras);
}
return intent;
}
protected void getIntentSender(Method method, Object[] args) {
String hostPackageName = mPluginManager.getHostContext().getPackageName();
args[1] = hostPackageName;
Intent target = ((Intent[]) args[5])[0];
int intentSenderType = (int)args[0];
if (intentSenderType == INTENT_SENDER_ACTIVITY) {
mPluginManager.getComponentsHandler().transformIntentToExplicitAsNeeded(target);
mPluginManager.getComponentsHandler().markIntentIfNeeded(target);
} else if (intentSenderType == INTENT_SENDER_SERVICE) {
ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
if (resolveInfo != null && resolveInfo.serviceInfo != null) {
// find plugin service
Intent wrapperIntent = wrapperTargetIntent(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_START_SERVICE);
((Intent[]) args[5])[0] = wrapperIntent;
}
} else if (intentSenderType == INTENT_SENDER_BROADCAST) {
// no action
}
}
protected void overridePendingTransition(Method method, Object[] args) {
String hostPackageName = mPluginManager.getHostContext().getPackageName();
args[1] = hostPackageName;
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/delegate/IContentProviderProxy.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk.delegate;
import android.content.Context;
import android.content.IContentProvider;
import android.content.pm.ProviderInfo;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import com.didi.virtualapk.PluginManager;
import com.didi.virtualapk.internal.Constants;
import com.didi.virtualapk.internal.LoadedPlugin;
import com.didi.virtualapk.internal.PluginContentResolver;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
/**
* Created by renyugang on 16/12/8.
*/
public class IContentProviderProxy implements InvocationHandler {
private static final String TAG = Constants.TAG_PREFIX + "IContentProviderProxy";
private IContentProvider mBase;
private Context mContext;
private IContentProviderProxy(Context context, IContentProvider iContentProvider) {
mBase = iContentProvider;
mContext = context;
}
public static IContentProvider newInstance(Context context, IContentProvider iContentProvider) {
return (IContentProvider) Proxy.newProxyInstance(iContentProvider.getClass().getClassLoader(),
new Class[] { IContentProvider.class }, new IContentProviderProxy(context, iContentProvider));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.v(TAG, method.toGenericString() + " : " + Arrays.toString(args));
wrapperUri(method, args);
try {
return method.invoke(mBase, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
private void wrapperUri(Method method, Object[] args) {
Uri uri = null;
int index = 0;
if (args != null) {
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Uri) {
uri = (Uri) args[i];
index = i;
break;
}
}
}
Bundle bundleInCallMethod = null;
if (method.getName().equals("call")) {
bundleInCallMethod = getBundleParameter(args);
if (bundleInCallMethod != null) {
String uriString = bundleInCallMethod.getString(RemoteContentProvider.KEY_WRAPPER_URI);
if (uriString != null) {
uri = Uri.parse(uriString);
}
}
}
if (uri == null) {
return;
}
PluginManager pluginManager = PluginManager.getInstance(mContext);
ProviderInfo info = pluginManager.resolveContentProvider(uri.getAuthority(), 0);
if (info != null) {
String pkg = info.packageName;
LoadedPlugin plugin = pluginManager.getLoadedPlugin(pkg);
Uri wrapperUri = PluginContentResolver.wrapperUri(plugin, uri);
if (method.getName().equals("call")) {
bundleInCallMethod.putString(RemoteContentProvider.KEY_WRAPPER_URI, wrapperUri.toString());
} else {
args[index] = wrapperUri;
}
}
}
private Bundle getBundleParameter(Object[] args) {
Bundle bundle = null;
if (args != null) {
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Bundle) {
bundle = (Bundle) args[i];
break;
}
}
}
return bundle;
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/delegate/LocalService.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk.delegate;
import android.app.ActivityThread;
import android.app.Application;
import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import com.didi.virtualapk.PluginManager;
import com.didi.virtualapk.internal.Constants;
import com.didi.virtualapk.internal.LoadedPlugin;
import com.didi.virtualapk.internal.utils.PluginUtil;
import com.didi.virtualapk.utils.Reflector;
import java.lang.reflect.Method;
/**
* @author johnsonlee
*/
public class LocalService extends Service {
private static final String TAG = Constants.TAG_PREFIX + "LocalService";
/**
* The target service, usually it's a plugin service intent
*/
public static final String EXTRA_TARGET = "target";
public static final String EXTRA_COMMAND = "command";
public static final String EXTRA_PLUGIN_LOCATION = "plugin_location";
public static final int EXTRA_COMMAND_START_SERVICE = 1;
public static final int EXTRA_COMMAND_STOP_SERVICE = 2;
public static final int EXTRA_COMMAND_BIND_SERVICE = 3;
public static final int EXTRA_COMMAND_UNBIND_SERVICE = 4;
private PluginManager mPluginManager;
@Override
public IBinder onBind(Intent intent) {
return new Binder();
}
@Override
public void onCreate() {
super.onCreate();
mPluginManager = PluginManager.getInstance(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (null == intent || !intent.hasExtra(EXTRA_TARGET) || !intent.hasExtra(EXTRA_COMMAND)) {
return START_STICKY;
}
Intent target = intent.getParcelableExtra(EXTRA_TARGET);
int command = intent.getIntExtra(EXTRA_COMMAND, 0);
if (null == target || command <= 0) {
return START_STICKY;
}
ComponentName component = target.getComponent();
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (plugin == null) {
Log.w(TAG, "Error target: " + target.toURI());
return START_STICKY;
}
// ClassNotFoundException when unmarshalling in Android 5.1
target.setExtrasClassLoader(plugin.getClassLoader());
switch (command) {
case EXTRA_COMMAND_START_SERVICE: {
ActivityThread mainThread = ActivityThread.currentActivityThread();
IApplicationThread appThread = mainThread.getApplicationThread();
Service service;
if (this.mPluginManager.getComponentsHandler().isServiceAvailable(component)) {
service = this.mPluginManager.getComponentsHandler().getService(component);
} else {
try {
service = (Service) plugin.getClassLoader().loadClass(component.getClassName()).newInstance();
Application app = plugin.getApplication();
IBinder token = appThread.asBinder();
Method attach = service.getClass().getMethod("attach", Context.class, ActivityThread.class, String.class, IBinder.class, Application.class, Object.class);
IActivityManager am = mPluginManager.getActivityManager();
attach.invoke(service, plugin.getPluginContext(), mainThread, component.getClassName(), token, app, am);
service.onCreate();
this.mPluginManager.getComponentsHandler().rememberService(component, service);
} catch (Throwable t) {
return START_STICKY;
}
}
service.onStartCommand(target, 0, this.mPluginManager.getComponentsHandler().getServiceCounter(service).getAndIncrement());
break;
}
case EXTRA_COMMAND_BIND_SERVICE: {
ActivityThread mainThread = ActivityThread.currentActivityThread();
IApplicationThread appThread = mainThread.getApplicationThread();
Service service = null;
if (this.mPluginManager.getComponentsHandler().isServiceAvailable(component)) {
service = this.mPluginManager.getComponentsHandler().getService(component);
} else {
try {
service = (Service) plugin.getClassLoader().loadClass(component.getClassName()).newInstance();
Application app = plugin.getApplication();
IBinder token = appThread.asBinder();
Method attach = service.getClass().getMethod("attach", Context.class, ActivityThread.class, String.class, IBinder.class, Application.class, Object.class);
IActivityManager am = mPluginManager.getActivityManager();
attach.invoke(service, plugin.getPluginContext(), mainThread, component.getClassName(), token, app, am);
service.onCreate();
this.mPluginManager.getComponentsHandler().rememberService(component, service);
} catch (Throwable t) {
Log.w(TAG, t);
}
}
try {
IBinder binder = service.onBind(target);
IBinder serviceConnection = PluginUtil.getBinder(intent.getExtras(), "sc");
IServiceConnection iServiceConnection = IServiceConnection.Stub.asInterface(serviceConnection);
if (Build.VERSION.SDK_INT >= 26) {
iServiceConnection.connected(component, binder, false);
} else {
Reflector.QuietReflector.with(iServiceConnection).method("connected", ComponentName.class, IBinder.class).call(component, binder);
}
} catch (Exception e) {
Log.w(TAG, e);
}
break;
}
case EXTRA_COMMAND_STOP_SERVICE: {
Service service = this.mPluginManager.getComponentsHandler().forgetService(component);
if (null != service) {
try {
service.onDestroy();
} catch (Exception e) {
Log.e(TAG, "Unable to stop service " + service + ": " + e.toString());
}
} else {
Log.i(TAG, component + " not found");
}
break;
}
case EXTRA_COMMAND_UNBIND_SERVICE: {
Service service = this.mPluginManager.getComponentsHandler().forgetService(component);
if (null != service) {
try {
service.onUnbind(target);
service.onDestroy();
} catch (Exception e) {
Log.e(TAG, "Unable to unbind service " + service + ": " + e.toString());
}
} else {
Log.i(TAG, component + " not found");
}
break;
}
}
return START_STICKY;
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/delegate/RemoteContentProvider.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk.delegate;
import android.content.ContentProvider;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import com.didi.virtualapk.PluginManager;
import com.didi.virtualapk.internal.Constants;
import com.didi.virtualapk.internal.LoadedPlugin;
import com.didi.virtualapk.utils.RunUtil;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Created by renyugang on 16/12/7.
*/
public class RemoteContentProvider extends ContentProvider {
private static final String TAG = Constants.TAG_PREFIX + "RemoteContentProvider";
public static final String KEY_PKG = "pkg";
public static final String KEY_PLUGIN = "plugin";
public static final String KEY_URI = "uri";
public static final String KEY_WRAPPER_URI = "wrapper_uri";
private static Map sCachedProviders = new HashMap<>();
@Override
public boolean onCreate() {
Log.d(TAG, "onCreate, current thread:"
+ Thread.currentThread().getName());
return true;
}
private ContentProvider getContentProvider(final Uri uri) {
final PluginManager pluginManager = PluginManager.getInstance(getContext());
Uri pluginUri = Uri.parse(uri.getQueryParameter(KEY_URI));
final String auth = pluginUri.getAuthority();
ContentProvider cachedProvider = sCachedProviders.get(auth);
if (cachedProvider != null) {
return cachedProvider;
}
synchronized (sCachedProviders) {
LoadedPlugin plugin = pluginManager.getLoadedPlugin(uri.getQueryParameter(KEY_PKG));
if (plugin == null) {
try {
pluginManager.loadPlugin(new File(uri.getQueryParameter(KEY_PLUGIN)));
} catch (Exception e) {
Log.w(TAG, e);
}
}
final ProviderInfo providerInfo = pluginManager.resolveContentProvider(auth, 0);
if (providerInfo != null) {
RunUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
LoadedPlugin loadedPlugin = pluginManager.getLoadedPlugin(uri.getQueryParameter(KEY_PKG));
ContentProvider contentProvider = (ContentProvider) Class.forName(providerInfo.name).newInstance();
contentProvider.attachInfo(loadedPlugin.getPluginContext(), providerInfo);
sCachedProviders.put(auth, contentProvider);
} catch (Exception e) {
Log.w(TAG, e);
}
}
}, true);
return sCachedProviders.get(auth);
}
}
return null;
}
@Override
public String getType(Uri uri) {
ContentProvider provider = getContentProvider(uri);
Uri pluginUri = Uri.parse(uri.getQueryParameter(KEY_URI));
if (provider != null) {
return provider.getType(pluginUri);
}
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
ContentProvider provider = getContentProvider(uri);
Uri pluginUri = Uri.parse(uri.getQueryParameter(KEY_URI));
if (provider != null) {
return provider.query(pluginUri, projection, selection, selectionArgs, sortOrder);
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
ContentProvider provider = getContentProvider(uri);
Uri pluginUri = Uri.parse(uri.getQueryParameter(KEY_URI));
if (provider != null) {
return provider.insert(pluginUri, values);
}
return uri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
ContentProvider provider = getContentProvider(uri);
Uri pluginUri = Uri.parse(uri.getQueryParameter(KEY_URI));
if (provider != null) {
return provider.delete(pluginUri, selection, selectionArgs);
}
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
ContentProvider provider = getContentProvider(uri);
Uri pluginUri = Uri.parse(uri.getQueryParameter(KEY_URI));
if (provider != null) {
return provider.update(pluginUri, values, selection, selectionArgs);
}
return 0;
}
@Override
public int bulkInsert(Uri uri, ContentValues[] values) {
ContentProvider provider = getContentProvider(uri);
Uri pluginUri = Uri.parse(uri.getQueryParameter(KEY_URI));
if (provider != null) {
return provider.bulkInsert(pluginUri, values);
}
return 0;
}
@NonNull
@Override
public ContentProviderResult[] applyBatch(ArrayList operations) throws OperationApplicationException {
try {
Field uriField = ContentProviderOperation.class.getDeclaredField("mUri");
uriField.setAccessible(true);
for (ContentProviderOperation operation : operations) {
Uri pluginUri = Uri.parse(operation.getUri().getQueryParameter(KEY_URI));
uriField.set(operation, pluginUri);
}
} catch (Exception e) {
return new ContentProviderResult[0];
}
if (operations.size() > 0) {
ContentProvider provider = getContentProvider(operations.get(0).getUri());
if (provider != null) {
return provider.applyBatch(operations);
}
}
return new ContentProviderResult[0];
}
@Override
public Bundle call(String method, String arg, Bundle extras) {
Log.d(TAG, "call " + method + " with extras : " + extras);
if (extras == null || extras.getString(KEY_WRAPPER_URI) == null) {
return null;
}
Uri uri = Uri.parse(extras.getString(KEY_WRAPPER_URI));
ContentProvider provider = getContentProvider(uri);
if (provider != null) {
return provider.call(method, arg, extras);
}
return null;
}
public static String getAuthority(Context context) {
return context.getPackageName() + ".VirtualAPK.Provider";
}
public static String getUri(Context context) {
return "content://" + getAuthority(context);
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/delegate/RemoteService.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk.delegate;
import android.content.ComponentName;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.didi.virtualapk.PluginManager;
import com.didi.virtualapk.internal.Constants;
import com.didi.virtualapk.internal.LoadedPlugin;
import java.io.File;
/**
* @author johnsonlee
*/
public class RemoteService extends LocalService {
private static final String TAG = Constants.TAG_PREFIX + "RemoteService";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent == null) {
return super.onStartCommand(intent, flags, startId);
}
Intent target = intent.getParcelableExtra(EXTRA_TARGET);
if (target != null) {
String pluginLocation = intent.getStringExtra(EXTRA_PLUGIN_LOCATION);
ComponentName component = target.getComponent();
LoadedPlugin plugin = PluginManager.getInstance(this).getLoadedPlugin(component);
if (plugin == null && pluginLocation != null) {
try {
PluginManager.getInstance(this).loadPlugin(new File(pluginLocation));
} catch (Exception e) {
Log.w(TAG, e);
}
}
}
return super.onStartCommand(intent, flags, startId);
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/delegate/StubActivity.java
================================================
package com.didi.virtualapk.delegate;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.support.annotation.Nullable;
/**
* Created by qiaopu on 2018/6/13.
*/
public class StubActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Go to the main activity
Intent mainIntent = getPackageManager().getLaunchIntentForPackage(getPackageName());
if (mainIntent == null) {
mainIntent = new Intent(Intent.ACTION_MAIN);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
mainIntent.setPackage(getPackageName());
ResolveInfo resolveInfo = getPackageManager().resolveActivity(mainIntent, 0);
if (resolveInfo != null) {
mainIntent.setClassName(this, resolveInfo.activityInfo.name);
}
}
startActivity(mainIntent);
finish();
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/internal/ActivityLifecycleCallbacksProxy.java
================================================
package com.didi.virtualapk.internal;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.Application;
import android.os.Bundle;
import com.didi.virtualapk.utils.Reflector;
import java.util.ArrayList;
/**
* Created by qiaopu on 2017/8/9.
*/
class ActivityLifecycleCallbacksProxy implements Application.ActivityLifecycleCallbacks {
final ArrayList mActivityLifecycleCallbacks =
Reflector.QuietReflector.with(ActivityThread.currentApplication()).field("mActivityLifecycleCallbacks").get();
Object[] collectActivityLifecycleCallbacks() {
if (mActivityLifecycleCallbacks == null) {
return null;
}
Object[] callbacks = null;
synchronized (mActivityLifecycleCallbacks) {
if (mActivityLifecycleCallbacks.size() > 0) {
callbacks = mActivityLifecycleCallbacks.toArray();
}
}
return callbacks;
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i = 0; i < callbacks.length; i++) {
((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityCreated(activity,
savedInstanceState);
}
}
}
@Override
public void onActivityStarted(Activity activity) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i = 0; i < callbacks.length; i++) {
((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityStarted(activity);
}
}
}
@Override
public void onActivityResumed(Activity activity) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i = 0; i < callbacks.length; i++) {
((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityResumed(activity);
}
}
}
@Override
public void onActivityPaused(Activity activity) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i = 0; i < callbacks.length; i++) {
((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityPaused(activity);
}
}
}
@Override
public void onActivityStopped(Activity activity) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i = 0; i < callbacks.length; i++) {
((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityStopped(activity);
}
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i = 0; i < callbacks.length; i++) {
((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivitySaveInstanceState(activity,
outState);
}
}
}
@Override
public void onActivityDestroyed(Activity activity) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i = 0; i < callbacks.length; i++) {
((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityDestroyed(activity);
}
}
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/internal/ComponentsHandler.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk.internal;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.IBinder;
import android.support.v4.util.ArrayMap;
import android.util.Log;
import com.didi.virtualapk.PluginManager;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by renyugang on 17/6/7.
*/
public class ComponentsHandler {
public static final String TAG = Constants.TAG_PREFIX + "PluginManager";
private Context mContext;
private PluginManager mPluginManager;
private StubActivityInfo mStubActivityInfo = new StubActivityInfo();
private ArrayMap mServices = new ArrayMap();
private ArrayMap mBoundServices = new ArrayMap();
private ArrayMap mServiceCounters = new ArrayMap();
public ComponentsHandler(PluginManager pluginManager) {
mPluginManager = pluginManager;
mContext = pluginManager.getHostContext();
}
/**
* transform intent from implicit to explicit
*/
public Intent transformIntentToExplicitAsNeeded(Intent intent) {
ComponentName component = intent.getComponent();
if (component == null
|| component.getPackageName().equals(mContext.getPackageName())) {
ResolveInfo info = mPluginManager.resolveActivity(intent);
if (info != null && info.activityInfo != null) {
component = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
intent.setComponent(component);
}
}
return intent;
}
public void markIntentIfNeeded(Intent intent) {
if (intent.getComponent() == null) {
return;
}
String targetPackageName = intent.getComponent().getPackageName();
String targetClassName = intent.getComponent().getClassName();
// search map and return specific launchmode stub activity
if (!targetPackageName.equals(mContext.getPackageName()) && mPluginManager.getLoadedPlugin(targetPackageName) != null) {
intent.putExtra(Constants.KEY_IS_PLUGIN, true);
intent.putExtra(Constants.KEY_TARGET_PACKAGE, targetPackageName);
intent.putExtra(Constants.KEY_TARGET_ACTIVITY, targetClassName);
dispatchStubActivity(intent);
}
}
private void dispatchStubActivity(Intent intent) {
ComponentName component = intent.getComponent();
String targetClassName = intent.getComponent().getClassName();
LoadedPlugin loadedPlugin = mPluginManager.getLoadedPlugin(intent);
ActivityInfo info = loadedPlugin.getActivityInfo(component);
if (info == null) {
throw new RuntimeException("can not find " + component);
}
int launchMode = info.launchMode;
Resources.Theme themeObj = loadedPlugin.getResources().newTheme();
themeObj.applyStyle(info.theme, true);
String stubActivity = mStubActivityInfo.getStubActivity(targetClassName, launchMode, themeObj);
Log.i(TAG, String.format("dispatchStubActivity,[%s -> %s]", targetClassName, stubActivity));
intent.setClassName(mContext, stubActivity);
}
public AtomicInteger getServiceCounter(Service service) {
return this.mServiceCounters.get(service);
}
/**
* Retrieve the started service by component name
*
* @param component
* @return
*/
public Service getService(ComponentName component) {
return this.mServices.get(component);
}
/**
* Put the started service into service registry, and then increase the counter associate with
* the service
*
* @param component
* @param service
*/
public void rememberService(ComponentName component, Service service) {
synchronized (this.mServices) {
this.mServices.put(component, service);
this.mServiceCounters.put(service, new AtomicInteger(0));
}
}
/**
* Remove the service from service registry
*
* @param component
* @return
*/
public Service forgetService(ComponentName component) {
synchronized (this.mServices) {
Service service = this.mServices.remove(component);
this.mServiceCounters.remove(service);
return service;
}
}
/**
* Remove the bound service from service registry
*
* @param iServiceConnection IServiceConnection binder when unbindService
* @return
*/
public Intent forgetIServiceConnection(IBinder iServiceConnection) {
synchronized (this.mBoundServices) {
Intent intent = this.mBoundServices.remove(iServiceConnection);
return intent;
}
}
/**
* save the bound service
*
* @param iServiceConnection IServiceConnection binder when bindService
* @return
*/
public void remberIServiceConnection(IBinder iServiceConnection, Intent intent) {
synchronized (this.mBoundServices) {
mBoundServices.put(iServiceConnection, intent);
}
}
/**
* Check if a started service with the specified component exists in the registry
*
* @param component
* @return
*/
public boolean isServiceAvailable(ComponentName component) {
return this.mServices.containsKey(component);
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/internal/Constants.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk.internal;
/**
* Created by renyugang on 16/8/15.
*/
public class Constants {
public static final String KEY_IS_PLUGIN = "isPlugin";
public static final String KEY_TARGET_PACKAGE = "target.package";
public static final String KEY_TARGET_ACTIVITY = "target.activity";
public static final String OPTIMIZE_DIR = "dex";
public static final String NATIVE_DIR = "valibs";
public static final boolean COMBINE_RESOURCES = true;
public static final boolean COMBINE_CLASSLOADER = true;
public static final boolean DEBUG = true;
public static final String TAG = "VA";
public static final String TAG_PREFIX = TAG + ".";
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/internal/LoadedPlugin.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk.internal;
import android.annotation.TargetApi;
import android.app.Application;
import android.app.Instrumentation;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ChangedPackages;
import android.content.pm.FeatureInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.VersionedPackage;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.didi.virtualapk.PluginManager;
import com.didi.virtualapk.internal.utils.DexUtil;
import com.didi.virtualapk.internal.utils.PackageParserCompat;
import com.didi.virtualapk.internal.utils.PluginUtil;
import com.didi.virtualapk.utils.Reflector;
import com.didi.virtualapk.utils.RunUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import dalvik.system.DexClassLoader;
/**
* Created by renyugang on 16/8/9.
*/
public class LoadedPlugin {
public static final String TAG = Constants.TAG_PREFIX + "LoadedPlugin";
protected File getDir(Context context, String name) {
return context.getDir(name, Context.MODE_PRIVATE);
}
protected ClassLoader createClassLoader(Context context, File apk, File libsDir, ClassLoader parent) throws Exception {
File dexOutputDir = getDir(context, Constants.OPTIMIZE_DIR);
String dexOutputPath = dexOutputDir.getAbsolutePath();
DexClassLoader loader = new DexClassLoader(apk.getAbsolutePath(), dexOutputPath, libsDir.getAbsolutePath(), parent);
if (Constants.COMBINE_CLASSLOADER) {
DexUtil.insertDex(loader, parent, libsDir);
}
return loader;
}
protected AssetManager createAssetManager(Context context, File apk) throws Exception {
AssetManager am = AssetManager.class.newInstance();
Reflector.with(am).method("addAssetPath", String.class).call(apk.getAbsolutePath());
return am;
}
protected Resources createResources(Context context, String packageName, File apk) throws Exception {
if (Constants.COMBINE_RESOURCES) {
return ResourcesManager.createResources(context, packageName, apk);
} else {
Resources hostResources = context.getResources();
AssetManager assetManager = createAssetManager(context, apk);
return new Resources(assetManager, hostResources.getDisplayMetrics(), hostResources.getConfiguration());
}
}
protected PluginPackageManager createPluginPackageManager() {
return new PluginPackageManager();
}
public PluginContext createPluginContext(Context context) {
if (context == null) {
return new PluginContext(this);
}
return new PluginContext(this, context);
}
protected ResolveInfo chooseBestActivity(Intent intent, String s, int flags, List query) {
return query.get(0);
}
protected final String mLocation;
protected PluginManager mPluginManager;
protected Context mHostContext;
protected Context mPluginContext;
protected final File mNativeLibDir;
protected final PackageParser.Package mPackage;
protected final PackageInfo mPackageInfo;
protected Resources mResources;
protected ClassLoader mClassLoader;
protected PluginPackageManager mPackageManager;
protected Map mActivityInfos;
protected Map mServiceInfos;
protected Map mReceiverInfos;
protected Map mProviderInfos;
protected Map mProviders; // key is authorities of provider
protected Map mInstrumentationInfos;
protected Application mApplication;
public LoadedPlugin(PluginManager pluginManager, Context context, File apk) throws Exception {
this.mPluginManager = pluginManager;
this.mHostContext = context;
this.mLocation = apk.getAbsolutePath();
this.mPackage = PackageParserCompat.parsePackage(context, apk, PackageParser.PARSE_MUST_BE_APK);
this.mPackage.applicationInfo.metaData = this.mPackage.mAppMetaData;
this.mPackageInfo = new PackageInfo();
this.mPackageInfo.applicationInfo = this.mPackage.applicationInfo;
this.mPackageInfo.applicationInfo.sourceDir = apk.getAbsolutePath();
if (Build.VERSION.SDK_INT >= 28
|| (Build.VERSION.SDK_INT == 27 && Build.VERSION.PREVIEW_SDK_INT != 0)) { // Android P Preview
try {
this.mPackageInfo.signatures = this.mPackage.mSigningDetails.signatures;
} catch (Throwable e) {
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
this.mPackageInfo.signatures = info.signatures;
}
} else {
this.mPackageInfo.signatures = this.mPackage.mSignatures;
}
this.mPackageInfo.packageName = this.mPackage.packageName;
if (pluginManager.getLoadedPlugin(mPackageInfo.packageName) != null) {
throw new RuntimeException("plugin has already been loaded : " + mPackageInfo.packageName);
}
this.mPackageInfo.versionCode = this.mPackage.mVersionCode;
this.mPackageInfo.versionName = this.mPackage.mVersionName;
this.mPackageInfo.permissions = new PermissionInfo[0];
this.mPackageManager = createPluginPackageManager();
this.mPluginContext = createPluginContext(null);
this.mNativeLibDir = getDir(context, Constants.NATIVE_DIR);
this.mPackage.applicationInfo.nativeLibraryDir = this.mNativeLibDir.getAbsolutePath();
this.mResources = createResources(context, getPackageName(), apk);
this.mClassLoader = createClassLoader(context, apk, this.mNativeLibDir, context.getClassLoader());
tryToCopyNativeLib(apk);
// Cache instrumentations
Map instrumentations = new HashMap();
for (PackageParser.Instrumentation instrumentation : this.mPackage.instrumentation) {
instrumentations.put(instrumentation.getComponentName(), instrumentation.info);
}
this.mInstrumentationInfos = Collections.unmodifiableMap(instrumentations);
this.mPackageInfo.instrumentation = instrumentations.values().toArray(new InstrumentationInfo[instrumentations.size()]);
// Cache activities
Map activityInfos = new HashMap();
for (PackageParser.Activity activity : this.mPackage.activities) {
activity.info.metaData = activity.metaData;
activityInfos.put(activity.getComponentName(), activity.info);
}
this.mActivityInfos = Collections.unmodifiableMap(activityInfos);
this.mPackageInfo.activities = activityInfos.values().toArray(new ActivityInfo[activityInfos.size()]);
// Cache services
Map serviceInfos = new HashMap();
for (PackageParser.Service service : this.mPackage.services) {
serviceInfos.put(service.getComponentName(), service.info);
}
this.mServiceInfos = Collections.unmodifiableMap(serviceInfos);
this.mPackageInfo.services = serviceInfos.values().toArray(new ServiceInfo[serviceInfos.size()]);
// Cache providers
Map providers = new HashMap();
Map providerInfos = new HashMap();
for (PackageParser.Provider provider : this.mPackage.providers) {
providers.put(provider.info.authority, provider.info);
providerInfos.put(provider.getComponentName(), provider.info);
}
this.mProviders = Collections.unmodifiableMap(providers);
this.mProviderInfos = Collections.unmodifiableMap(providerInfos);
this.mPackageInfo.providers = providerInfos.values().toArray(new ProviderInfo[providerInfos.size()]);
// Register broadcast receivers dynamically
Map receivers = new HashMap();
for (PackageParser.Activity receiver : this.mPackage.receivers) {
receivers.put(receiver.getComponentName(), receiver.info);
BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance());
for (PackageParser.ActivityIntentInfo aii : receiver.intents) {
this.mHostContext.registerReceiver(br, aii);
}
}
this.mReceiverInfos = Collections.unmodifiableMap(receivers);
this.mPackageInfo.receivers = receivers.values().toArray(new ActivityInfo[receivers.size()]);
// try to invoke plugin's application
invokeApplication();
}
protected void tryToCopyNativeLib(File apk) throws Exception {
PluginUtil.copyNativeLib(apk, mHostContext, mPackageInfo, mNativeLibDir);
}
public String getLocation() {
return this.mLocation;
}
public String getPackageName() {
return this.mPackage.packageName;
}
public PackageManager getPackageManager() {
return this.mPackageManager;
}
public AssetManager getAssets() {
return getResources().getAssets();
}
public Resources getResources() {
return this.mResources;
}
public void updateResources(Resources newResources) {
this.mResources = newResources;
}
public ClassLoader getClassLoader() {
return this.mClassLoader;
}
public PluginManager getPluginManager() {
return this.mPluginManager;
}
public Context getHostContext() {
return this.mHostContext;
}
public Context getPluginContext() {
return this.mPluginContext;
}
public Application getApplication() {
return mApplication;
}
public void invokeApplication() throws Exception {
final Exception[] temp = new Exception[1];
// make sure application's callback is run on ui thread.
RunUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
if (mApplication != null) {
return;
}
try {
mApplication = makeApplication(false, mPluginManager.getInstrumentation());
} catch (Exception e) {
temp[0] = e;
}
}
}, true);
if (temp[0] != null) {
throw temp[0];
}
}
public String getPackageResourcePath() {
int myUid = Process.myUid();
ApplicationInfo appInfo = this.mPackage.applicationInfo;
return appInfo.uid == myUid ? appInfo.sourceDir : appInfo.publicSourceDir;
}
public String getCodePath() {
return this.mPackage.applicationInfo.sourceDir;
}
public Intent getLaunchIntent() {
ContentResolver resolver = this.mPluginContext.getContentResolver();
Intent launcher = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
for (PackageParser.Activity activity : this.mPackage.activities) {
for (PackageParser.ActivityIntentInfo intentInfo : activity.intents) {
if (intentInfo.match(resolver, launcher, false, TAG) > 0) {
return Intent.makeMainActivity(activity.getComponentName());
}
}
}
return null;
}
public Intent getLeanbackLaunchIntent() {
ContentResolver resolver = this.mPluginContext.getContentResolver();
Intent launcher = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
for (PackageParser.Activity activity : this.mPackage.activities) {
for (PackageParser.ActivityIntentInfo intentInfo : activity.intents) {
if (intentInfo.match(resolver, launcher, false, TAG) > 0) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(activity.getComponentName());
intent.addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
return intent;
}
}
}
return null;
}
public ApplicationInfo getApplicationInfo() {
return this.mPackage.applicationInfo;
}
public PackageInfo getPackageInfo() {
return this.mPackageInfo;
}
public ActivityInfo getActivityInfo(ComponentName componentName) {
return this.mActivityInfos.get(componentName);
}
public ServiceInfo getServiceInfo(ComponentName componentName) {
return this.mServiceInfos.get(componentName);
}
public ActivityInfo getReceiverInfo(ComponentName componentName) {
return this.mReceiverInfos.get(componentName);
}
public ProviderInfo getProviderInfo(ComponentName componentName) {
return this.mProviderInfos.get(componentName);
}
public Resources.Theme getTheme() {
Resources.Theme theme = this.mResources.newTheme();
theme.applyStyle(PluginUtil.selectDefaultTheme(this.mPackage.applicationInfo.theme, Build.VERSION.SDK_INT), false);
return theme;
}
public void setTheme(int resid) {
Reflector.QuietReflector.with(this.mResources).field("mThemeResId").set(resid);
}
protected Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) throws Exception {
if (null != this.mApplication) {
return this.mApplication;
}
String appClass = this.mPackage.applicationInfo.className;
if (forceDefaultAppClass || null == appClass) {
appClass = "android.app.Application";
}
this.mApplication = instrumentation.newApplication(this.mClassLoader, appClass, this.getPluginContext());
// inject activityLifecycleCallbacks of the host application
mApplication.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksProxy());
instrumentation.callApplicationOnCreate(this.mApplication);
return this.mApplication;
}
public ResolveInfo resolveActivity(Intent intent, int flags) {
List query = this.queryIntentActivities(intent, flags);
if (null == query || query.isEmpty()) {
return null;
}
ContentResolver resolver = this.mPluginContext.getContentResolver();
return chooseBestActivity(intent, intent.resolveTypeIfNeeded(resolver), flags, query);
}
public List queryIntentActivities(Intent intent, int flags) {
ComponentName component = intent.getComponent();
List resolveInfos = new ArrayList();
ContentResolver resolver = this.mPluginContext.getContentResolver();
for (PackageParser.Activity activity : this.mPackage.activities) {
if (match(activity, component)) {
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = activity.info;
resolveInfos.add(resolveInfo);
} else if (component == null) {
// only match implicit intent
for (PackageParser.ActivityIntentInfo intentInfo : activity.intents) {
if (intentInfo.match(resolver, intent, true, TAG) >= 0) {
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = activity.info;
resolveInfos.add(resolveInfo);
break;
}
}
}
}
return resolveInfos;
}
public ResolveInfo resolveService(Intent intent, int flags) {
List query = this.queryIntentServices(intent, flags);
if (null == query || query.isEmpty()) {
return null;
}
ContentResolver resolver = this.mPluginContext.getContentResolver();
return chooseBestActivity(intent, intent.resolveTypeIfNeeded(resolver), flags, query);
}
public List queryIntentServices(Intent intent, int flags) {
ComponentName component = intent.getComponent();
List resolveInfos = new ArrayList();
ContentResolver resolver = this.mPluginContext.getContentResolver();
for (PackageParser.Service service : this.mPackage.services) {
if (match(service, component)) {
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.serviceInfo = service.info;
resolveInfos.add(resolveInfo);
} else if (component == null) {
// only match implicit intent
for (PackageParser.ServiceIntentInfo intentInfo : service.intents) {
if (intentInfo.match(resolver, intent, true, TAG) >= 0) {
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.serviceInfo = service.info;
resolveInfos.add(resolveInfo);
break;
}
}
}
}
return resolveInfos;
}
public List queryBroadcastReceivers(Intent intent, int flags) {
ComponentName component = intent.getComponent();
List resolveInfos = new ArrayList();
ContentResolver resolver = this.mPluginContext.getContentResolver();
for (PackageParser.Activity receiver : this.mPackage.receivers) {
if (receiver.getComponentName().equals(component)) {
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = receiver.info;
resolveInfos.add(resolveInfo);
} else if (component == null) {
// only match implicit intent
for (PackageParser.ActivityIntentInfo intentInfo : receiver.intents) {
if (intentInfo.match(resolver, intent, true, TAG) >= 0) {
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = receiver.info;
resolveInfos.add(resolveInfo);
break;
}
}
}
}
return resolveInfos;
}
public ProviderInfo resolveContentProvider(String name, int flags) {
return this.mProviders.get(name);
}
protected boolean match(PackageParser.Component component, ComponentName target) {
ComponentName source = component.getComponentName();
if (source == target) return true;
if (source != null && target != null
&& source.getClassName().equals(target.getClassName())
&& (source.getPackageName().equals(target.getPackageName())
|| mHostContext.getPackageName().equals(target.getPackageName()))) {
return true;
}
return false;
}
/**
* @author johnsonlee
*/
protected class PluginPackageManager extends PackageManager {
protected PackageManager mHostPackageManager = mHostContext.getPackageManager();
@Override
public PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName);
if (null != plugin) {
return plugin.mPackageInfo;
}
return this.mHostPackageManager.getPackageInfo(packageName, flags);
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public PackageInfo getPackageInfo(VersionedPackage versionedPackage, int i) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(versionedPackage.getPackageName());
if (null != plugin) {
return plugin.mPackageInfo;
}
return this.mHostPackageManager.getPackageInfo(versionedPackage, i);
}
@Override
public String[] currentToCanonicalPackageNames(String[] names) {
return this.mHostPackageManager.currentToCanonicalPackageNames(names);
}
@Override
public String[] canonicalToCurrentPackageNames(String[] names) {
return this.mHostPackageManager.canonicalToCurrentPackageNames(names);
}
@Override
public Intent getLaunchIntentForPackage(@NonNull String packageName) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName);
if (null != plugin) {
return plugin.getLaunchIntent();
}
return this.mHostPackageManager.getLaunchIntentForPackage(packageName);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public Intent getLeanbackLaunchIntentForPackage(@NonNull String packageName) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName);
if (null != plugin) {
return plugin.getLeanbackLaunchIntent();
}
return this.mHostPackageManager.getLeanbackLaunchIntentForPackage(packageName);
}
@Override
public int[] getPackageGids(@NonNull String packageName) throws NameNotFoundException {
return this.mHostPackageManager.getPackageGids(packageName);
}
@TargetApi(Build.VERSION_CODES.N)
@Override
public int[] getPackageGids(String packageName, int flags) throws NameNotFoundException {
return this.mHostPackageManager.getPackageGids(packageName, flags);
}
@TargetApi(Build.VERSION_CODES.N)
@Override
public int getPackageUid(String packageName, int flags) throws NameNotFoundException {
return this.mHostPackageManager.getPackageUid(packageName, flags);
}
@Override
public PermissionInfo getPermissionInfo(String name, int flags) throws NameNotFoundException {
return this.mHostPackageManager.getPermissionInfo(name, flags);
}
@Override
public List queryPermissionsByGroup(String group, int flags) throws NameNotFoundException {
return this.mHostPackageManager.queryPermissionsByGroup(group, flags);
}
@Override
public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) throws NameNotFoundException {
return this.mHostPackageManager.getPermissionGroupInfo(name, flags);
}
@Override
public List getAllPermissionGroups(int flags) {
return this.mHostPackageManager.getAllPermissionGroups(flags);
}
@Override
public ApplicationInfo getApplicationInfo(String packageName, int flags) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName);
if (null != plugin) {
return plugin.getApplicationInfo();
}
return this.mHostPackageManager.getApplicationInfo(packageName, flags);
}
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
return plugin.mActivityInfos.get(component);
}
return this.mHostPackageManager.getActivityInfo(component, flags);
}
@Override
public ActivityInfo getReceiverInfo(ComponentName component, int flags) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
return plugin.mReceiverInfos.get(component);
}
return this.mHostPackageManager.getReceiverInfo(component, flags);
}
@Override
public ServiceInfo getServiceInfo(ComponentName component, int flags) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
return plugin.mServiceInfos.get(component);
}
return this.mHostPackageManager.getServiceInfo(component, flags);
}
@Override
public ProviderInfo getProviderInfo(ComponentName component, int flags) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
return plugin.mProviderInfos.get(component);
}
return this.mHostPackageManager.getProviderInfo(component, flags);
}
@Override
public List getInstalledPackages(int flags) {
return this.mHostPackageManager.getInstalledPackages(flags);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override
public List getPackagesHoldingPermissions(String[] permissions, int flags) {
return this.mHostPackageManager.getPackagesHoldingPermissions(permissions, flags);
}
@Override
public int checkPermission(String permName, String pkgName) {
return this.mHostPackageManager.checkPermission(permName, pkgName);
}
@TargetApi(Build.VERSION_CODES.M)
@Override
public boolean isPermissionRevokedByPolicy(@NonNull String permName, @NonNull String pkgName) {
return this.mHostPackageManager.isPermissionRevokedByPolicy(permName, pkgName);
}
@Override
public boolean addPermission(PermissionInfo info) {
return this.mHostPackageManager.addPermission(info);
}
@Override
public boolean addPermissionAsync(PermissionInfo info) {
return this.mHostPackageManager.addPermissionAsync(info);
}
@Override
public void removePermission(String name) {
this.mHostPackageManager.removePermission(name);
}
@Override
public int checkSignatures(String pkg1, String pkg2) {
return this.mHostPackageManager.checkSignatures(pkg1, pkg2);
}
@Override
public int checkSignatures(int uid1, int uid2) {
return this.mHostPackageManager.checkSignatures(uid1, uid2);
}
@Override
public String[] getPackagesForUid(int uid) {
return this.mHostPackageManager.getPackagesForUid(uid);
}
@Override
public String getNameForUid(int uid) {
return this.mHostPackageManager.getNameForUid(uid);
}
@Override
public List getInstalledApplications(int flags) {
return this.mHostPackageManager.getInstalledApplications(flags);
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public boolean isInstantApp() {
return this.mHostPackageManager.isInstantApp();
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public boolean isInstantApp(String packageName) {
return this.mHostPackageManager.isInstantApp(packageName);
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public int getInstantAppCookieMaxBytes() {
return this.mHostPackageManager.getInstantAppCookieMaxBytes();
}
@TargetApi(Build.VERSION_CODES.O)
@NonNull
@Override
public byte[] getInstantAppCookie() {
return this.mHostPackageManager.getInstantAppCookie();
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public void clearInstantAppCookie() {
this.mHostPackageManager.clearInstantAppCookie();
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public void updateInstantAppCookie(@Nullable byte[] cookie) {
this.mHostPackageManager.updateInstantAppCookie(cookie);
}
@Override
public String[] getSystemSharedLibraryNames() {
return this.mHostPackageManager.getSystemSharedLibraryNames();
}
@TargetApi(Build.VERSION_CODES.O)
@NonNull
@Override
public List getSharedLibraries(int flags) {
return this.mHostPackageManager.getSharedLibraries(flags);
}
@TargetApi(Build.VERSION_CODES.O)
@Nullable
@Override
public ChangedPackages getChangedPackages(int sequenceNumber) {
return this.mHostPackageManager.getChangedPackages(sequenceNumber);
}
@Override
public FeatureInfo[] getSystemAvailableFeatures() {
return this.mHostPackageManager.getSystemAvailableFeatures();
}
@Override
public boolean hasSystemFeature(String name) {
return this.mHostPackageManager.hasSystemFeature(name);
}
@TargetApi(Build.VERSION_CODES.N)
@Override
public boolean hasSystemFeature(String name, int version) {
return this.mHostPackageManager.hasSystemFeature(name, version);
}
@Override
public ResolveInfo resolveActivity(Intent intent, int flags) {
ResolveInfo resolveInfo = mPluginManager.resolveActivity(intent, flags);
if (null != resolveInfo) {
return resolveInfo;
}
return this.mHostPackageManager.resolveActivity(intent, flags);
}
@Override
public List queryIntentActivities(Intent intent, int flags) {
ComponentName component = intent.getComponent();
if (null == component) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
component = intent.getComponent();
}
}
if (null != component) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
ActivityInfo activityInfo = plugin.getActivityInfo(component);
if (activityInfo != null) {
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = activityInfo;
return Arrays.asList(resolveInfo);
}
}
}
List all = new ArrayList();
List pluginResolveInfos = mPluginManager.queryIntentActivities(intent, flags);
if (null != pluginResolveInfos && pluginResolveInfos.size() > 0) {
all.addAll(pluginResolveInfos);
}
List hostResolveInfos = this.mHostPackageManager.queryIntentActivities(intent, flags);
if (null != hostResolveInfos && hostResolveInfos.size() > 0) {
all.addAll(hostResolveInfos);
}
return all;
}
@Override
public List queryIntentActivityOptions(ComponentName caller, Intent[] specifics, Intent intent, int flags) {
return this.mHostPackageManager.queryIntentActivityOptions(caller, specifics, intent, flags);
}
@Override
public List queryBroadcastReceivers(Intent intent, int flags) {
ComponentName component = intent.getComponent();
if (null == component) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
component = intent.getComponent();
}
}
if (null != component) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
ActivityInfo activityInfo = plugin.getReceiverInfo(component);
if (activityInfo != null) {
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = activityInfo;
return Arrays.asList(resolveInfo);
}
}
}
List all = new ArrayList<>();
List pluginResolveInfos = mPluginManager.queryBroadcastReceivers(intent, flags);
if (null != pluginResolveInfos && pluginResolveInfos.size() > 0) {
all.addAll(pluginResolveInfos);
}
List hostResolveInfos = this.mHostPackageManager.queryBroadcastReceivers(intent, flags);
if (null != hostResolveInfos && hostResolveInfos.size() > 0) {
all.addAll(hostResolveInfos);
}
return all;
}
@Override
public ResolveInfo resolveService(Intent intent, int flags) {
ResolveInfo resolveInfo = mPluginManager.resolveService(intent, flags);
if (null != resolveInfo) {
return resolveInfo;
}
return this.mHostPackageManager.resolveService(intent, flags);
}
@Override
public List queryIntentServices(Intent intent, int flags) {
ComponentName component = intent.getComponent();
if (null == component) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
component = intent.getComponent();
}
}
if (null != component) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
ServiceInfo serviceInfo = plugin.getServiceInfo(component);
if (serviceInfo != null) {
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.serviceInfo = serviceInfo;
return Arrays.asList(resolveInfo);
}
}
}
List all = new ArrayList();
List pluginResolveInfos = mPluginManager.queryIntentServices(intent, flags);
if (null != pluginResolveInfos && pluginResolveInfos.size() > 0) {
all.addAll(pluginResolveInfos);
}
List hostResolveInfos = this.mHostPackageManager.queryIntentServices(intent, flags);
if (null != hostResolveInfos && hostResolveInfos.size() > 0) {
all.addAll(hostResolveInfos);
}
return all;
}
@Override
@TargetApi(Build.VERSION_CODES.KITKAT)
public List queryIntentContentProviders(Intent intent, int flags) {
return this.mHostPackageManager.queryIntentContentProviders(intent, flags);
}
@Override
public ProviderInfo resolveContentProvider(String name, int flags) {
ProviderInfo providerInfo = mPluginManager.resolveContentProvider(name, flags);
if (null != providerInfo) {
return providerInfo;
}
return this.mHostPackageManager.resolveContentProvider(name, flags);
}
@Override
public List queryContentProviders(String processName, int uid, int flags) {
return this.mHostPackageManager.queryContentProviders(processName, uid, flags);
}
@Override
public InstrumentationInfo getInstrumentationInfo(ComponentName component, int flags) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
return plugin.mInstrumentationInfos.get(component);
}
return this.mHostPackageManager.getInstrumentationInfo(component, flags);
}
@Override
public List queryInstrumentation(String targetPackage, int flags) {
return this.mHostPackageManager.queryInstrumentation(targetPackage, flags);
}
@Override
public Drawable getDrawable(String packageName, int resid, ApplicationInfo appInfo) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName);
if (null != plugin) {
return plugin.mResources.getDrawable(resid);
}
return this.mHostPackageManager.getDrawable(packageName, resid, appInfo);
}
@Override
public Drawable getActivityIcon(ComponentName component) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
return plugin.mResources.getDrawable(plugin.mActivityInfos.get(component).icon);
}
return this.mHostPackageManager.getActivityIcon(component);
}
@Override
public Drawable getActivityIcon(Intent intent) throws NameNotFoundException {
ResolveInfo ri = mPluginManager.resolveActivity(intent);
if (null != ri) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(ri.resolvePackageName);
return plugin.mResources.getDrawable(ri.activityInfo.icon);
}
return this.mHostPackageManager.getActivityIcon(intent);
}
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public Drawable getActivityBanner(ComponentName component) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
return plugin.mResources.getDrawable(plugin.mActivityInfos.get(component).banner);
}
return this.mHostPackageManager.getActivityBanner(component);
}
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public Drawable getActivityBanner(Intent intent) throws NameNotFoundException {
ResolveInfo ri = mPluginManager.resolveActivity(intent);
if (null != ri) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(ri.resolvePackageName);
return plugin.mResources.getDrawable(ri.activityInfo.banner);
}
return this.mHostPackageManager.getActivityBanner(intent);
}
@Override
public Drawable getDefaultActivityIcon() {
return this.mHostPackageManager.getDefaultActivityIcon();
}
@Override
public Drawable getApplicationIcon(ApplicationInfo info) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(info.packageName);
if (null != plugin) {
return plugin.mResources.getDrawable(info.icon);
}
return this.mHostPackageManager.getApplicationIcon(info);
}
@Override
public Drawable getApplicationIcon(String packageName) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName);
if (null != plugin) {
return plugin.mResources.getDrawable(plugin.mPackage.applicationInfo.icon);
}
return this.mHostPackageManager.getApplicationIcon(packageName);
}
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public Drawable getApplicationBanner(ApplicationInfo info) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(info.packageName);
if (null != plugin) {
return plugin.mResources.getDrawable(info.banner);
}
return this.mHostPackageManager.getApplicationBanner(info);
}
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public Drawable getApplicationBanner(String packageName) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName);
if (null != plugin) {
return plugin.mResources.getDrawable(plugin.mPackage.applicationInfo.banner);
}
return this.mHostPackageManager.getApplicationBanner(packageName);
}
@Override
public Drawable getActivityLogo(ComponentName component) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
return plugin.mResources.getDrawable(plugin.mActivityInfos.get(component).logo);
}
return this.mHostPackageManager.getActivityLogo(component);
}
@Override
public Drawable getActivityLogo(Intent intent) throws NameNotFoundException {
ResolveInfo ri = mPluginManager.resolveActivity(intent);
if (null != ri) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(ri.resolvePackageName);
return plugin.mResources.getDrawable(ri.activityInfo.logo);
}
return this.mHostPackageManager.getActivityLogo(intent);
}
@Override
public Drawable getApplicationLogo(ApplicationInfo info) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(info.packageName);
if (null != plugin) {
return plugin.mResources.getDrawable(0 != info.logo ? info.logo : android.R.drawable.sym_def_app_icon);
}
return this.mHostPackageManager.getApplicationLogo(info);
}
@Override
public Drawable getApplicationLogo(String packageName) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName);
if (null != plugin) {
return plugin.mResources.getDrawable(0 != plugin.mPackage.applicationInfo.logo ? plugin.mPackage.applicationInfo.logo : android.R.drawable.sym_def_app_icon);
}
return this.mHostPackageManager.getApplicationLogo(packageName);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
return this.mHostPackageManager.getUserBadgedIcon(icon, user);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public Drawable getUserBadgeForDensity(UserHandle user, int density) {
try {
return Reflector.with(this.mHostPackageManager)
.method("getUserBadgeForDensity", UserHandle.class, int.class)
.call(user, density);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public Drawable getUserBadgedDrawableForDensity(Drawable drawable, UserHandle user, Rect badgeLocation, int badgeDensity) {
return this.mHostPackageManager.getUserBadgedDrawableForDensity(drawable, user, badgeLocation, badgeDensity);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) {
return this.mHostPackageManager.getUserBadgedLabel(label, user);
}
@Override
public CharSequence getText(String packageName, int resid, ApplicationInfo appInfo) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName);
if (null != plugin) {
return plugin.mResources.getText(resid);
}
return this.mHostPackageManager.getText(packageName, resid, appInfo);
}
@Override
public XmlResourceParser getXml(String packageName, int resid, ApplicationInfo appInfo) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName);
if (null != plugin) {
return plugin.mResources.getXml(resid);
}
return this.mHostPackageManager.getXml(packageName, resid, appInfo);
}
@Override
public CharSequence getApplicationLabel(ApplicationInfo info) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(info.packageName);
if (null != plugin) {
try {
return plugin.mResources.getText(info.labelRes);
} catch (Resources.NotFoundException e) {
// ignored.
}
}
return this.mHostPackageManager.getApplicationLabel(info);
}
@Override
public Resources getResourcesForActivity(ComponentName component) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
if (null != plugin) {
return plugin.mResources;
}
return this.mHostPackageManager.getResourcesForActivity(component);
}
@Override
public Resources getResourcesForApplication(ApplicationInfo app) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(app.packageName);
if (null != plugin) {
return plugin.mResources;
}
return this.mHostPackageManager.getResourcesForApplication(app);
}
@Override
public Resources getResourcesForApplication(String appPackageName) throws NameNotFoundException {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(appPackageName);
if (null != plugin) {
return plugin.mResources;
}
return this.mHostPackageManager.getResourcesForApplication(appPackageName);
}
@Override
public void verifyPendingInstall(int id, int verificationCode) {
this.mHostPackageManager.verifyPendingInstall(id, verificationCode);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay) {
this.mHostPackageManager.extendVerificationTimeout(id, verificationCodeAtTimeout, millisecondsToDelay);
}
@Override
public void setInstallerPackageName(String targetPackage, String installerPackageName) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(targetPackage);
if (null != plugin) {
return;
}
this.mHostPackageManager.setInstallerPackageName(targetPackage, installerPackageName);
}
@Override
public String getInstallerPackageName(String packageName) {
LoadedPlugin plugin = mPluginManager.getLoadedPlugin(packageName);
if (null != plugin) {
return mHostContext.getPackageName();
}
return this.mHostPackageManager.getInstallerPackageName(packageName);
}
@Override
public void addPackageToPreferred(String packageName) {
this.mHostPackageManager.addPackageToPreferred(packageName);
}
@Override
public void removePackageFromPreferred(String packageName) {
this.mHostPackageManager.removePackageFromPreferred(packageName);
}
@Override
public List getPreferredPackages(int flags) {
return this.mHostPackageManager.getPreferredPackages(flags);
}
@Override
public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
this.mHostPackageManager.addPreferredActivity(filter, match, set, activity);
}
@Override
public void clearPackagePreferredActivities(String packageName) {
this.mHostPackageManager.clearPackagePreferredActivities(packageName);
}
@Override
public int getPreferredActivities(@NonNull List outFilters, @NonNull List outActivities, String packageName) {
return this.mHostPackageManager.getPreferredActivities(outFilters, outActivities, packageName);
}
@Override
public void setComponentEnabledSetting(ComponentName component, int newState, int flags) {
this.mHostPackageManager.setComponentEnabledSetting(component, newState, flags);
}
@Override
public int getComponentEnabledSetting(ComponentName component) {
return this.mHostPackageManager.getComponentEnabledSetting(component);
}
@Override
public void setApplicationEnabledSetting(String packageName, int newState, int flags) {
this.mHostPackageManager.setApplicationEnabledSetting(packageName, newState, flags);
}
@Override
public int getApplicationEnabledSetting(String packageName) {
return this.mHostPackageManager.getApplicationEnabledSetting(packageName);
}
@Override
public boolean isSafeMode() {
return this.mHostPackageManager.isSafeMode();
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public void setApplicationCategoryHint(@NonNull String packageName, int categoryHint) {
this.mHostPackageManager.setApplicationCategoryHint(packageName, categoryHint);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public @NonNull PackageInstaller getPackageInstaller() {
return this.mHostPackageManager.getPackageInstaller();
}
@TargetApi(Build.VERSION_CODES.O)
@Override
public boolean canRequestPackageInstalls() {
return this.mHostPackageManager.canRequestPackageInstalls();
}
public Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
if (itemInfo == null) {
return null;
}
return itemInfo.loadIcon(this.mHostPackageManager);
}
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/internal/PluginContentResolver.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk.internal;
import android.annotation.TargetApi;
import android.content.ContentResolverWrapper;
import android.content.Context;
import android.content.IContentProvider;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Keep;
import com.didi.virtualapk.PluginManager;
import com.didi.virtualapk.delegate.RemoteContentProvider;
/**
* Created by renyugang on 16/12/7.
*/
public class PluginContentResolver extends ContentResolverWrapper {
private PluginManager mPluginManager;
public PluginContentResolver(Context context) {
super(context);
mPluginManager = PluginManager.getInstance(context);
}
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
if (mPluginManager.resolveContentProvider(auth, 0) != null) {
return mPluginManager.getIContentProvider();
}
return super.acquireProvider(context, auth);
}
@Override
protected IContentProvider acquireExistingProvider(Context context, String auth) {
if (mPluginManager.resolveContentProvider(auth, 0) != null) {
return mPluginManager.getIContentProvider();
}
return super.acquireExistingProvider(context, auth);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
protected IContentProvider acquireUnstableProvider(Context context, String auth) {
if (mPluginManager.resolveContentProvider(auth, 0) != null) {
return mPluginManager.getIContentProvider();
}
return super.acquireUnstableProvider(context, auth);
}
@Override
public boolean releaseProvider(IContentProvider provider) {
return true;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public boolean releaseUnstableProvider(IContentProvider icp) {
return true;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void unstableProviderDied(IContentProvider icp) {
}
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@Override
public void appNotRespondingViaProvider(IContentProvider icp) {
}
protected int resolveUserIdFromAuthority(String auth) {
return 0;
}
@Keep
public static Uri wrapperUri(LoadedPlugin loadedPlugin, Uri pluginUri) {
String pkg = loadedPlugin.getPackageName();
String pluginUriString = Uri.encode(pluginUri.toString());
StringBuilder builder = new StringBuilder(RemoteContentProvider.getUri(loadedPlugin.getHostContext()));
builder.append("/?plugin=" + loadedPlugin.getLocation());
builder.append("&pkg=" + pkg);
builder.append("&uri=" + pluginUriString);
Uri wrapperUri = Uri.parse(builder.toString());
return wrapperUri;
}
@Deprecated
public static String getAuthority(Context context) {
return RemoteContentProvider.getAuthority(context);
}
@Deprecated
public static String getUri(Context context) {
return RemoteContentProvider.getUri(context);
}
@Keep
public static Bundle getBundleForCall(Uri uri) {
Bundle bundle = new Bundle();
bundle.putString(RemoteContentProvider.KEY_WRAPPER_URI, uri.toString());
return bundle;
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/internal/PluginContext.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk.internal;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
/**
* Created by renyugang on 16/8/12.
*/
class PluginContext extends ContextWrapper {
private final LoadedPlugin mPlugin;
public PluginContext(LoadedPlugin plugin) {
super(plugin.getPluginManager().getHostContext());
this.mPlugin = plugin;
}
public PluginContext(LoadedPlugin plugin, Context base) {
super(base);
this.mPlugin = plugin;
}
@Override
public Context getApplicationContext() {
return this.mPlugin.getApplication();
}
// @Override
// public ApplicationInfo getApplicationInfo() {
// return this.mPlugin.getApplicationInfo();
// }
private Context getHostContext() {
return getBaseContext();
}
@Override
public ContentResolver getContentResolver() {
return new PluginContentResolver(getHostContext());
}
@Override
public ClassLoader getClassLoader() {
return this.mPlugin.getClassLoader();
}
// @Override
// public String getPackageName() {
// return this.mPlugin.getPackageName();
// }
// @Override
// public String getPackageResourcePath() {
// return this.mPlugin.getPackageResourcePath();
// }
// @Override
// public String getPackageCodePath() {
// return this.mPlugin.getCodePath();
// }
@Override
public PackageManager getPackageManager() {
return this.mPlugin.getPackageManager();
}
@Override
public Object getSystemService(String name) {
// intercept CLIPBOARD_SERVICE,NOTIFICATION_SERVICE
if (name.equals(Context.CLIPBOARD_SERVICE)) {
return getHostContext().getSystemService(name);
} else if (name.equals(Context.NOTIFICATION_SERVICE)) {
return getHostContext().getSystemService(name);
}
return super.getSystemService(name);
}
@Override
public Resources getResources() {
return this.mPlugin.getResources();
}
@Override
public AssetManager getAssets() {
return this.mPlugin.getAssets();
}
@Override
public Resources.Theme getTheme() {
return this.mPlugin.getTheme();
}
@Override
public void startActivity(Intent intent) {
ComponentsHandler componentsHandler = mPlugin.getPluginManager().getComponentsHandler();
componentsHandler.transformIntentToExplicitAsNeeded(intent);
super.startActivity(intent);
}
}
================================================
FILE: CoreLibrary/src/main/java/com/didi/virtualapk/internal/ResourcesManager.java
================================================
/*
* Copyright (C) 2017 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.didi.virtualapk.internal;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.LoadedApk;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.ResourcesImpl;
import android.content.res.ResourcesKey;
import android.os.Build;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.Log;
import com.didi.virtualapk.PluginManager;
import com.didi.virtualapk.utils.Reflector;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Created by renyugang on 16/8/9.
*/
class ResourcesManager {
public static final String TAG = Constants.TAG_PREFIX + "LoadedPlugin";
private static Configuration mDefaultConfiguration;
public static synchronized Resources createResources(Context hostContext, String packageName, File apk) throws Exception {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return createResourcesForN(hostContext, packageName, apk);
}
Resources resources = ResourcesManager.createResourcesSimple(hostContext, apk.getAbsolutePath());
ResourcesManager.hookResources(hostContext, resources);
return resources;
}
private static Resources createResourcesSimple(Context hostContext, String apk) throws Exception {
Resources hostResources = hostContext.getResources();
Resources newResources = null;
AssetManager assetManager;
Reflector reflector = Reflector.on(AssetManager.class).method("addAssetPath", String.class);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
assetManager = AssetManager.class.newInstance();
reflector.bind(assetManager);
final int cookie1 = reflector.call(hostContext.getApplicationInfo().sourceDir);;
if (cookie1 == 0) {
throw new RuntimeException("createResources failed, can't addAssetPath for " + hostContext.getApplicationInfo().sourceDir);
}
} else {
assetManager = hostResources.getAssets();
reflector.bind(assetManager);
}
final int cookie2 = reflector.call(apk);
if (cookie2 == 0) {
throw new RuntimeException("createResources failed, can't addAssetPath for " + apk);
}
List pluginList = PluginManager.getInstance(hostContext).getAllLoadedPlugins();
for (LoadedPlugin plugin : pluginList) {
final int cookie3 = reflector.call(plugin.getLocation());
if (cookie3 == 0) {
throw new RuntimeException("createResources failed, can't addAssetPath for " + plugin.getLocation());
}
}
if (isMiUi(hostResources)) {
newResources = MiUiResourcesCompat.createResources(hostResources, assetManager);
} else if (isVivo(hostResources)) {
newResources = VivoResourcesCompat.createResources(hostContext, hostResources, assetManager);
} else if (isNubia(hostResources)) {
newResources = NubiaResourcesCompat.createResources(hostResources, assetManager);
} else if (isNotRawResources(hostResources)) {
newResources = AdaptationResourcesCompat.createResources(hostResources, assetManager);
} else {
// is raw android resources
newResources = new Resources(assetManager, hostResources.getDisplayMetrics(), hostResources.getConfiguration());
}
// lastly, sync all LoadedPlugin to newResources
for (LoadedPlugin plugin : pluginList) {
plugin.updateResources(newResources);
}
return newResources;
}
public static void hookResources(Context base, Resources resources) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return;
}
try {
Reflector reflector = Reflector.with(base);
reflector.field("mResources").set(resources);
Object loadedApk = reflector.field("mPackageInfo").get();
Reflector.with(loadedApk).field("mResources").set(resources);
Object activityThread = ActivityThread.currentActivityThread();
Object resManager;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
resManager = android.app.ResourcesManager.getInstance();
} else {
resManager = Reflector.with(activityThread).field("mResourcesManager").get();
}
Map