diff --git a/README.md b/README.md
index 323d8430..a6946dd8 100644
--- a/README.md
+++ b/README.md
@@ -5,9 +5,10 @@
[![license](http://img.shields.io/badge/license-Apache2.0-brightgreen.svg?style=flat)](https://github.com/Qihoo360/RePlugin/blob/master/LICENSE)
-[![Release Version](https://img.shields.io/badge/release-2.2.4-brightgreen.svg)](https://github.com/Qihoo360/RePlugin/releases)
-
+[![Release Version](https://img.shields.io/badge/release-2.3.1-brightgreen.svg)](https://github.com/Qihoo360/RePlugin/releases)
+## 活动通知
+移动技术最新活动通知:9月1号360移动技术开放日 http://t.cn/RDiNru9
## RePlugin —— A flexible, stable, easy-to-use Android Plug-in Framework
@@ -55,6 +56,9 @@ At present, almost **all Apps with hundreds of millions users from 360, and many
## Our Vision
Make RePlugin be used in all kinds of ordinary Apps; and provide stable, flexible, liberal plug-ins which adopt for both large and small projects.
+## Latest features
+Solved the Android P (Android 9.0) related adaptation issues, fully support the official version of Android P (Android 9.0).
+
## RePlugin Architecture
diff --git a/README_CN.md b/README_CN.md
index 63bc3517..85b84bc4 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -6,7 +6,7 @@
[![license](http://img.shields.io/badge/license-Apache2.0-brightgreen.svg?style=flat)](https://github.com/Qihoo360/RePlugin/blob/master/LICENSE)
-[![Release Version](https://img.shields.io/badge/release-2.2.4-brightgreen.svg)](https://github.com/Qihoo360/RePlugin/releases)
+[![Release Version](https://img.shields.io/badge/release-2.3.1-brightgreen.svg)](https://github.com/Qihoo360/RePlugin/releases)
@@ -57,6 +57,10 @@ RePlugin是一套完整的、稳定的、适合全面使用的,占坑类插件
让插件化能**飞入寻常应用家**,做到稳定、灵活、自由,大小项目兼用。
+## 最新特性
+
+解决了Android P(Android 9.0)相关适配问题,全面支持Android P(Android 9.0)正式版。
+
## RePlugin 架构图
diff --git a/deploy.sh b/deploy.sh
new file mode 100755
index 00000000..0f37f936
--- /dev/null
+++ b/deploy.sh
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+export RP_BASE_DIR=$(cd "$(dirname "$0")"; pwd)
+
+export TARGET_PROJECTS=(
+replugin-host-gradle
+replugin-host-library
+replugin-plugin-gradle
+replugin-plugin-library
+)
+
+__gradle_exec(){ if [[ -x gradlew ]];then ./gradlew ${@}; else gradle ${@}; fi; }
+
+__rp_deploy_project(){
+ [[ ! -d ${1} ]] && echo ">>> INVALID ${1}!!! <<<" && return
+ # execute deploying
+ echo ">>> ${1} <<<" && __gradle_exec -p ${1} clean bintrayUpload
+ # revert changed files
+ git checkout ${1}
+}
+
+rp_deploy(){
+ local current=`pwd` && cd ${RP_BASE_DIR}
+ # saving all changes: git stash save "saving stash for deploying!!!"
+ # deploy
+ for p in ${TARGET_PROJECTS}; do __rp_deploy_project ${RP_BASE_DIR}/${p}; done
+ # revert local changes: git revert --hard HEAD; git stash pop
+ local current=`pwd`
+}
+
+rp_test(){
+ local projects=(
+ # replugin-sample/host/app
+ replugin-sample/host
+ # replugin-sample/plugin/plugin-demo1/app
+ replugin-sample/plugin/plugin-demo1
+ # replugin-sample/plugin/plugin-demo2/app
+ replugin-sample/plugin/plugin-demo2
+ # replugin-sample/plugin/plugin-demo3-kotlin/app
+ replugin-sample/plugin/plugin-demo3-kotlin
+ # replugin-sample/plugin/plugin-webview/app
+ replugin-sample/plugin/plugin-webview
+ # replugin-sample-extra/fresco/FrescoHost/app
+ replugin-sample-extra/fresco/FrescoHost
+ # replugin-sample-extra/fresco/FrescoPlugin/app
+ replugin-sample-extra/fresco/FrescoPlugin
+ )
+ local log=${RP_BASE_DIR}/build/rp_test.log && [[ -f $log ]] && rm -f $log
+ local current=`pwd`
+ for p in ${projects}; do
+ echo -e ">>> BUILDING ${p}"
+ p=${RP_BASE_DIR}/${p} && __gradle_exec -p ${p} clean asDebug 2>/dev/null >> ${log} && echo "SUCCEED";
+ ls -l ${p}/app/build/outputs/apk
+ done
+ cd ${current}
+}
+
+# grep --exclude-dir={.bzr,CVS,.git,.hg,.svn,.idea,build,.gradle} -inr '2\.3\.0' .
\ No newline at end of file
diff --git a/replugin-host-gradle/build.gradle b/replugin-host-gradle/build.gradle
index d698fbc2..6f08f2e8 100644
--- a/replugin-host-gradle/build.gradle
+++ b/replugin-host-gradle/build.gradle
@@ -30,6 +30,7 @@ buildscript {
jcenter()
mavenCentral()
}
+
dependencies {
// classpath 'com.android.tools.build:gradle:2.1.0'
// 将项目发布到JCenter 所需要的jar 添加依赖
@@ -38,14 +39,6 @@ buildscript {
}
}
-group = 'com.qihoo360.replugin' // 组名
-String classPath = ".src.main.groovy.com.qihoo360.replugin.gradle.host.AppConstant".replace(".", java.io.File.separator)
-String verPath = "${project.projectDir}" + classPath + ".groovy"
-String verLine = new File(verPath).filterLine { it =~ /def static final VER =/ }
-version = "${verLine.split("\"")[1]}" // 版本
-//红色醒目打印显示版本号
-java.lang.System.err.println "version=${version}"
-
dependencies {
compile 'com.android.tools.build:gradle:2.1.3'
compile 'org.json:json:20160212'
@@ -57,60 +50,7 @@ dependencies {
compile 'com.google.gradle:osdetector-gradle-plugin:1.2.1'
compile 'net.dongliu:apk-parser:2.2.0'
-
-}
-
-
-
-if (project.hasProperty("android")) { // Android libraries
- task sourcesJar(type: Jar) {
- classifier = 'sources'
- from android.sourceSets.main.java.srcDirs
- }
-
- task javadoc(type: Javadoc) {
- source = android.sourceSets.main.java.srcDirs
- classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
- }
-} else { // Java libraries
- task sourcesJar(type: Jar, dependsOn: classes) {
- classifier = 'sources'
- from sourceSets.main.allSource
- }
-}
-
-// 强制 Java/JavaDoc 等的编码为 UTF-8
-tasks.withType(JavaCompile) {
- options.encoding = "UTF-8"
}
-task javadocJar(type: Jar, dependsOn: javadoc) {
- classifier = 'javadoc'
- from javadoc.destinationDir
-}
-
-
-
-// add javadoc/source jar tasks as artifacts
-artifacts {
- archives sourcesJar, javadocJar
-}
-
-publishing {
- publications {
- mavenJava(MavenPublication) {
- if (plugins.hasPlugin('war')) {
- from components.web
- } else {
- from components.java
- }
-
- artifact sourcesJar
- artifact javadocJar
- }
- }
-}
-
-apply from: 'bintray.gradle'
-
-
+project.ext.RP_ARTIFACT_ID = 'replugin-host-gradle'
+apply from: '../rp-publish.gradle'
\ No newline at end of file
diff --git a/replugin-host-gradle/src/main/groovy/com/qihoo360/replugin/gradle/host/AppConstant.groovy b/replugin-host-gradle/src/main/groovy/com/qihoo360/replugin/gradle/host/AppConstant.groovy
index d0c1dada..a671b1af 100644
--- a/replugin-host-gradle/src/main/groovy/com/qihoo360/replugin/gradle/host/AppConstant.groovy
+++ b/replugin-host-gradle/src/main/groovy/com/qihoo360/replugin/gradle/host/AppConstant.groovy
@@ -23,7 +23,7 @@ package com.qihoo360.replugin.gradle.host
class AppConstant {
/** 版本号 */
- def static final VER = "2.3.0"
+ def static final VER = "${RP_VERSION}"
/** 打印信息时候的前缀 */
def static final TAG = "< replugin-host-v${VER} >"
diff --git a/replugin-host-library/replugin-host-lib/build.gradle b/replugin-host-library/replugin-host-lib/build.gradle
index fbfa6db4..1280694a 100644
--- a/replugin-host-library/replugin-host-lib/build.gradle
+++ b/replugin-host-library/replugin-host-lib/build.gradle
@@ -19,11 +19,6 @@
*/
apply plugin: 'com.android.library'
-
-version = "2.3.0"
-
-group = 'com.qihoo360.replugin' // 组名
-
android {
compileSdkVersion 25
buildToolsVersion '25.0.2'
@@ -54,4 +49,5 @@ dependencies {
provided 'com.android.support:support-v4:25.2.0'
}
-apply from: 'bintray.gradle'
+project.ext.RP_ARTIFACT_ID = 'replugin-host-lib'
+apply from: '../../rp-publish.gradle'
diff --git a/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/Loader.java b/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/Loader.java
index 518bc8e7..aa054aa3 100644
--- a/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/Loader.java
+++ b/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/Loader.java
@@ -17,6 +17,7 @@
package com.qihoo360.loader2;
import android.content.Context;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
@@ -382,12 +383,18 @@ final boolean loadDex(ClassLoader parent, int load) {
private void regReceivers() throws android.os.RemoteException {
String plugin = mPluginObj.mInfo.getName();
+ Map> map = ManifestParser.INS.getReceiverFilterMap(plugin);
+
+ if (map == null || map.size() == 0) {
+ return;
+ }
+
if (mPluginHost == null) {
mPluginHost = getPluginHost();
}
if (mPluginHost != null) {
- mPluginHost.regReceiver(plugin, ManifestParser.INS.getReceiverFilterMap(plugin));
+ mPluginHost.regReceiver(plugin, map);
}
}
diff --git a/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/PluginProcessMain.java b/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/PluginProcessMain.java
index 4751e567..c1ade55c 100644
--- a/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/PluginProcessMain.java
+++ b/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/PluginProcessMain.java
@@ -16,17 +16,15 @@
package com.qihoo360.loader2;
-import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
+import android.support.annotation.NonNull;
import android.text.TextUtils;
+import android.util.Log;
import com.qihoo360.i.IPluginManager;
-import com.qihoo360.mobilesafe.api.Tasks;
-import com.qihoo360.replugin.RePluginInternal;
-import com.qihoo360.replugin.base.AMSUtils;
import com.qihoo360.replugin.base.IPC;
import com.qihoo360.replugin.component.process.PluginProcessHost;
import com.qihoo360.replugin.helper.LogDebug;
@@ -44,6 +42,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import static com.qihoo360.replugin.helper.LogDebug.LOG;
import static com.qihoo360.replugin.helper.LogDebug.MAIN_TAG;
@@ -51,179 +50,66 @@
import static com.qihoo360.replugin.helper.LogRelease.LOGR;
/**
+ * 进程管理类
* @author RePlugin Team
*/
public class PluginProcessMain {
- private static final int STATE_UNUSED = 0;
-
- private static final int STATE_ALLOCATED = 1;
-
- private static final int STATE_RUNNING = 2;
-
-// private static final int STATE_MARKED = 3;
-
- private static final int STATE_STOPED = 4;
-
+ public static final String TAG = PluginProcessMain.class.getSimpleName();
/**
- *
+ * 常驻进程使用,非常驻进程为null buyuntao
*/
private static IPluginHost sPluginHostLocal;
/**
- *
+ * 非常驻进程使用,常驻进程为null,用于非常驻进程连接常驻进程 buyuntao
*/
private static IPluginHost sPluginHostRemote;
-
/**
- *
+ * 提供binder保存功能,无其他逻辑
*/
static HashMap sBinders = new HashMap();
-
/**
- * TODO 待重构 PROCESSES & ALL
- */
- private static final ProcessRecord PROCESSES[] = new ProcessRecord[Constant.STUB_PROCESS_COUNT];
-
- /**
- * TODO 待重构 PROCESSES & ALL
- * processName -> ProcessClientRecord
+ * 当前运行的所有进程的列表(常驻进程除外)
*/
private static final Map ALL = new HashMap();
-
- static {
- for (int i = 0; i < Constant.STUB_PROCESS_COUNT; i++) {
- ProcessRecord r = new ProcessRecord(i, STATE_UNUSED);
- PROCESSES[i] = r;
- }
- }
-
/**
- *
+ * ALL的读写锁,用于并发时的性能提升
*/
+ private static final ReentrantReadWriteLock PROCESS_CLIENT_LOCK = new ReentrantReadWriteLock();
private static final Object COOKIE_LOCK = new Object();
-
- /**
- *
- */
private static boolean sPersisistCookieInitialized;
-
/**
* 常驻进程cookie,用来控制卫士进程组是否需要退出等
*/
private static long sPersisistCookie;
- static final int CHECK_STAGE1_DELAY = 17 * 1000;
-
- private static final int CHECK_STAGE2_DELAY = 11 * 1000;
-
- private static final int CHECK_STAGE3_DELAY = 3 * 1000;
-
- private static final Runnable CHECK = new Runnable() {
-
- @Override
- public void run() {
- doPluginProcessLoop();
- }
- };
-
- private static final class ProcessRecord {
-
- final int index;
-
- int state;
-
- long mobified;
-
- String plugin;
-
- int pid;
-
- IBinder binder;
-
- IPluginClient client;
-
- int activities;
-
- int services;
-
- int binders;
-
- ProcessRecord(int index, int state) {
- this.index = index;
- this.state = state;
- }
-
- void allocate(String plugin) {
- this.state = STATE_ALLOCATED;
- this.mobified = System.currentTimeMillis();
- this.plugin = plugin;
- this.pid = 0;
- this.binder = null;
- this.client = null;
- this.activities = 0;
- this.services = 0;
- this.binders = 0;
- }
-
- void setRunning(int pid) {
- this.state = STATE_RUNNING;
- this.pid = pid;
- }
-
- void setClient(IBinder binder, IPluginClient client) {
- this.binder = binder;
- this.client = client;
- }
-
-// void setMarked() {
-// this.state = STATE_MARKED;
-// }
-
- void setStoped() {
- this.state = STATE_STOPED;
- this.pid = 0;
- this.binder = null;
- this.client = null;
- }
-
- @Override
- public String toString() {
- if (LOG) {
- return super.toString() + " {index=" + index + " state=" + state + " mobified=" + mobified + " plugin=" + plugin + " pid=" + pid + " binder=" + binder + " client=" + client
- + " activities=" + activities + " services=" + services + " binders=" + binders + "}";
- }
- return super.toString();
- }
- }
-
/**
- * 常驻进程使用
+ * 进程记录,用于进程及进程列表管理 buyuntao
*/
private static final class ProcessClientRecord implements IBinder.DeathRecipient {
- String name;
-
+ String name; //进程名称
String plugin;
-
int pid;
-
int index;
-
IBinder binder;
-
IPluginClient client;
+ PluginManagerServer pluginManager; //单个进程的插件管理类
- private final PluginManagerServer mManagerServer;
-
- // FIXME 不建议这么传递,但为了在死亡周期中使用,不得已而为之
- public ProcessClientRecord(PluginManagerServer pms) {
- mManagerServer = pms;
+ public ProcessClientRecord(String process, String plugin, int pid, int index, IBinder binder, IPluginClient client, PluginManagerServer pms) {
+ this.name = process;
+ this.plugin = plugin;
+ this.pid = pid;
+ this.index = index;
+ this.binder = binder;
+ this.client = client;
+ this.pluginManager = pms;
}
@Override
public void binderDied() {
- handleBinderDied(this, mManagerServer);
+ handleBinderDied(this);
}
@Override
@@ -238,18 +124,6 @@ public IPluginClient getClient() {
return client;
}
}
-
- static final void reportStatus() {
- for (ProcessRecord r : PROCESSES) {
- if (r.binder == null) {
- continue;
- }
- if (LOG) {
- LogDebug.i(PLUGIN_TAG, "i=" + r.index + " p=" + r.plugin + " a=" + r.activities + " s=" + r.services + " b=" + r.binders);
- }
- }
- }
-
static final String dump() {
// 1.dump Activity映射表, service列表
@@ -324,10 +198,7 @@ static final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
writer.println(r);
}
writer.println();
- writer.println("--- PROCESSES.length = " + PROCESSES.length + " ---");
- for (ProcessRecord r : PROCESSES) {
- writer.println(r);
- }
+ StubProcessManager.dump(writer);
writer.println();
// writer.println("--- USED_PLUGINS.size = " + USED_PLUGINS.size() + " ---");
// for (ProcessPluginInfo r : USED_PLUGINS.values()) {
@@ -360,8 +231,6 @@ static final void installHost(IPluginHost host) {
*/
static final void connectToHostSvc() {
Context context = PMF.getApplicationContext();
-
- //
IBinder binder = PluginProviderStub.proxyFetchHostBinder(context);
if (LOG) {
LogDebug.d(PLUGIN_TAG, "host binder = " + binder);
@@ -373,11 +242,8 @@ static final void connectToHostSvc() {
}
System.exit(1);
}
-
- //
try {
binder.linkToDeath(new IBinder.DeathRecipient() {
-
@Override
public void binderDied() {
if (LOGR) {
@@ -430,8 +296,11 @@ public void binderDied() {
// 注册该进程信息到“插件管理进程”中
PMF.sPluginMgr.attach();
}
-
- // @hide 内部框架使用
+ /**
+ * sPluginHostLocal 常驻进程使用,非常驻进程为null buyuntao
+ * sPluginHostRemote 非常驻进程使用,常驻进程为null,用于非常驻进程连接常驻进程 buyuntao
+ * @hide 内部框架使用
+ */
public static final IPluginHost getPluginHost() {
if (sPluginHostLocal != null) {
return sPluginHostLocal;
@@ -471,36 +340,39 @@ static final long getPersistentCookie() {
* @param info
* @return
*/
- static final IPluginClient probePluginClient(String plugin, int process, PluginBinderInfo info) {
- synchronized (PROCESSES) {
- for (ProcessClientRecord r : ALL.values()) {
- if (process == IPluginManager.PROCESS_UI) {
- if (!TextUtils.equals(r.plugin, Constant.PLUGIN_NAME_UI)) {
- continue;
- }
+ static final IPluginClient probePluginClient(final String plugin, final int process, final PluginBinderInfo info) {
+ return readProcessClientLock(new Action() {
+ @Override
+ public IPluginClient call() {
+ for (ProcessClientRecord r : ALL.values()) {
+ if (process == IPluginManager.PROCESS_UI) {
+ if (!TextUtils.equals(r.plugin, Constant.PLUGIN_NAME_UI)) {
+ continue;
+ }
- /* 是否是用户自定义进程 */
- } else if (PluginProcessHost.isCustomPluginProcess(process)) {
- if (!TextUtils.equals(r.plugin, getProcessStringByIndex(process))) {
- continue;
+ /* 是否是用户自定义进程 */
+ } else if (PluginProcessHost.isCustomPluginProcess(process)) {
+ if (!TextUtils.equals(r.plugin, getProcessStringByIndex(process))) {
+ continue;
+ }
+ } else {
+ if (!TextUtils.equals(r.plugin, plugin)) {
+ continue;
+ }
}
- } else {
- if (!TextUtils.equals(r.plugin, plugin)) {
- continue;
+ if (!isBinderAlive(r)) {
+ return null;
}
+ if (!r.binder.pingBinder()) {
+ return null;
+ }
+ info.pid = r.pid;
+ info.index = r.index;
+ return r.client;
}
- if (!isBinderAlive(r)) {
- return null;
- }
- if (!r.binder.pingBinder()) {
- return null;
- }
- info.pid = r.pid;
- info.index = r.index;
- return r.client;
+ return null;
}
- }
- return null;
+ });
}
/**
@@ -518,153 +390,160 @@ private static String getProcessStringByIndex(int index) {
* @param info
* @return
*/
- static final IPluginClient probePluginClientByPid(int pid, PluginBinderInfo info) {
- synchronized (PROCESSES) {
- for (ProcessClientRecord r : ALL.values()) {
- if (r.pid != pid) {
- continue;
- }
- if (!isBinderAlive(r)) {
- return null;
- }
- if (!r.binder.pingBinder()) {
- return null;
+ static final IPluginClient probePluginClientByPid(final int pid, final PluginBinderInfo info) {
+ return readProcessClientLock(new Action() {
+ @Override
+ public IPluginClient call() {
+ for (ProcessClientRecord r : ALL.values()) {
+ if (r.pid != pid) {
+ continue;
+ }
+ if (!isBinderAlive(r)) {
+ return null;
+ }
+ if (!r.binder.pingBinder()) {
+ return null;
+ }
+ info.pid = r.pid;
+ info.index = r.index;
+ return r.client;
}
- info.pid = r.pid;
- info.index = r.index;
- return r.client;
+ return null;
}
- }
- return null;
+ });
}
/**
+ * 发送intent给进程 buyuntao
* @param target
* @param intent
*/
- static final void sendIntent2Process(String target, Intent intent, boolean sync) {
- synchronized (PROCESSES) {
- for (ProcessClientRecord r : ALL.values()) {
- if (target == null || target.length() <= 0) {
- // 所有
- } else if (TextUtils.equals(r.name, target)) {
- // 特定目标
- } else {
- continue;
- }
- if (!isBinderAlive(r)) {
- continue;
- }
- if (LOG) {
- LogDebug.d(PLUGIN_TAG, "sendIntent2Process name=" + r.name);
- }
- try {
- if (sync) {
- r.client.sendIntentSync(intent);
+ static final void sendIntent2Process(final String target, Intent intent, boolean sync) {
+ final Map map = readProcessClientLock(new Action