Merge pull request #711 from bnotebook/dev

Performance improvement
This commit is contained in:
buyuntao 2018-11-14 16:22:55 +08:00 committed by GitHub
commit 89c40667b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 895 additions and 973 deletions

View File

@ -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 @@ class Loader {
private void regReceivers() throws android.os.RemoteException {
String plugin = mPluginObj.mInfo.getName();
Map<String, List<IntentFilter>> 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);
}
}

View File

@ -173,6 +173,34 @@ class PmBase {
*/
private static final byte[] LOCKER = new byte[0];
/**
* 广播接收器声明为成员变量以避免重复创建
*/
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (TextUtils.isEmpty(action)) {
return;
}
if (action.equals(intent.getAction())) {
PluginInfo info = intent.getParcelableExtra("obj");
if (info != null) {
switch (action) {
case ACTION_NEW_PLUGIN:
// 非常驻进程上下文
newPluginFound(info, intent.getBooleanExtra(RePluginConstants.KEY_PERSIST_NEED_RESTART, false));
break;
case ACTION_UNINSTALL_PLUGIN:
pluginUninstalled(info);
break;
}
}
}
}
};
/**
* 类映射
*/
@ -280,7 +308,7 @@ class PmBase {
mHostSvc = new PmHostSvc(mContext, this);
PluginProcessMain.installHost(mHostSvc);
PluginProcessMain.schedulePluginProcessLoop(PluginProcessMain.CHECK_STAGE1_DELAY);
StubProcessManager.schedulePluginProcessLoop(StubProcessManager.CHECK_STAGE1_DELAY);
// 兼容即将废弃的p-n方案 by Jiongxuan Zhang
mAll = new Builder.PxAll();
@ -619,36 +647,17 @@ class PmBase {
if (!IPC.isPersistentProcess()) {
// 由于常驻进程已经在内部做了相关的处理此处仅需要在UI进程注册并更新即可
registerReceiverAction(ACTION_NEW_PLUGIN);
registerReceiverAction(ACTION_UNINSTALL_PLUGIN);
}
}
/**
* @param action
*/
private final void registerReceiverAction(final String action) {
IntentFilter filter = new IntentFilter(action);
LocalBroadcastManager.getInstance(mContext).registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (action.equals(intent.getAction())) {
PluginInfo info = intent.getParcelableExtra("obj");
if (info != null) {
switch (action) {
case ACTION_NEW_PLUGIN:
// 非常驻进程上下文
newPluginFound(info, intent.getBooleanExtra(RePluginConstants.KEY_PERSIST_NEED_RESTART, false));
break;
case ACTION_UNINSTALL_PLUGIN:
pluginUninstalled(info);
break;
}
}
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_NEW_PLUGIN);
intentFilter.addAction(ACTION_UNINSTALL_PLUGIN);
try {
LocalBroadcastManager.getInstance(mContext).registerReceiver(mBroadcastReceiver, intentFilter);
} catch (Exception e) {
if (LOGR) {
LogRelease.e(PLUGIN_TAG, "p m hlc a r e: " + e.getMessage(), e);
}
}
}, filter);
}
}
/**
@ -1215,7 +1224,7 @@ class PmBase {
}
//
PluginProcessMain.schedulePluginProcessLoop(PluginProcessMain.CHECK_STAGE1_DELAY);
StubProcessManager.schedulePluginProcessLoop(StubProcessManager.CHECK_STAGE1_DELAY);
// 获取
IPluginClient client = PluginProcessMain.probePluginClient(plugin, process, info);
@ -1238,7 +1247,7 @@ class PmBase {
LogRelease.e(PLUGIN_TAG, "a.p.p: " + e.getMessage(), e);
}
}
// 分配的坑位不属于UI自定义进程就返回
// 分配的坑位不属于UI自定义进程或Stub坑位进程就返回没找到有效进程
if (!(index == IPluginManager.PROCESS_UI
|| PluginProcessHost.isCustomPluginProcess(index)
|| PluginManager.isPluginProcess(index))) {

View File

@ -177,9 +177,7 @@ class PmHostSvc extends IPluginHost.Stub {
@Override
public IPluginClient startPluginProcess(String plugin, int process, PluginBinderInfo info) throws RemoteException {
synchronized (this) {
return mPluginMgr.startPluginProcessLocked(plugin, process, info);
}
return mPluginMgr.startPluginProcessLocked(plugin, process, info);
}
@Override
@ -340,7 +338,6 @@ class PmHostSvc extends IPluginHost.Stub {
syncInstalledPluginInfo2All(pi);
}
return pi;
}
@ -484,28 +481,27 @@ class PmHostSvc extends IPluginHost.Stub {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "sendIntent2Process target=" + target + " intent=" + intent);
}
if (TextUtils.equals(target, IPC.getPluginHostProcessName())) {
intent.setExtrasClassLoader(getClass().getClassLoader());
if (sync) {
LocalBroadcastHelper.sendBroadcastSyncUi(mContext, intent);
} else {
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
}
sendIntent2PluginHostProcess(intent, sync);
return;
}
if (TextUtils.isEmpty(target)) {
intent.setExtrasClassLoader(getClass().getClassLoader());
if (sync) {
LocalBroadcastHelper.sendBroadcastSyncUi(mContext, intent);
} else {
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
}
sendIntent2PluginHostProcess(intent, sync);
}
PluginProcessMain.sendIntent2Process(target, intent, sync);
}
private void sendIntent2PluginHostProcess(Intent intent, boolean sync) {
intent.setExtrasClassLoader(getClass().getClassLoader());
if (sync) {
LocalBroadcastHelper.sendBroadcastSyncUi(mContext, intent);
} else {
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
}
}
@Override
public void sendIntent2Plugin(String target, Intent intent) throws RemoteException {
sendIntent2Plugin(target, intent, false);

View File

@ -0,0 +1,544 @@
package com.qihoo360.loader2;
import android.app.ActivityManager;
import android.os.IBinder;
import android.text.TextUtils;
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.helper.LogDebug;
import com.qihoo360.replugin.helper.LogRelease;
import java.io.PrintWriter;
import java.util.List;
import static com.qihoo360.replugin.helper.LogDebug.LOG;
import static com.qihoo360.replugin.helper.LogDebug.PLUGIN_TAG;
import static com.qihoo360.replugin.helper.LogRelease.LOGR;
/**
* @author RePlugin Team
* dec: 坑位进程管理 buyuntao
*/
public class StubProcessManager {
/**
* 坑位进程列表
*/
static final ProcessRecord STUB_PROCESSES[] = new ProcessRecord[Constant.STUB_PROCESS_COUNT];
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();
}
};
static {
for (int i = 0; i < Constant.STUB_PROCESS_COUNT; i++) {
ProcessRecord r = new ProcessRecord(i, StubProcessState.STATE_UNUSED);
STUB_PROCESSES[i] = r;
}
}
/**
* 分配坑位进程 buyuntao(外部调用端已经加锁)
* @param plugin
* @return 进程index值
*/
static final int allocProcess(String plugin) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "alloc plugin process: plugin=" + plugin);
}
// 取运行列表
List<ActivityManager.RunningAppProcessInfo> processes = AMSUtils.getRunningAppProcessesNoThrows(RePluginInternal.getAppContext());
// 取运行列表失败则直接返回失败
if (processes == null || processes.isEmpty()) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "alloc plugin process: get running processes is empty");
LogDebug.i(PLUGIN_TAG, "get list exception p=" + plugin);
}
return IPluginManager.PROCESS_AUTO;
}
//根据优先级分配坑位进程
int prevMatchPriority = -1; //临时变量保存上一个ProcessRecord的进程分配优先级
ProcessRecord selectRecord = null; //被选中的坑位进程
for (ProcessRecord r : STUB_PROCESSES) {
synchronized (r) {
if (r.calculateMatchPriority(plugin) > prevMatchPriority) {
prevMatchPriority = r.calculateMatchPriority(plugin);
selectRecord = r;
} else if (r.calculateMatchPriority(plugin) == prevMatchPriority) {
if (r.mobified < selectRecord.mobified) {
selectRecord = r;
}
}
}
}
if (selectRecord == null) { //不应该出现
return IPluginManager.PROCESS_AUTO;
}
synchronized (selectRecord){
//插件已在分配进程中运行直接返回
if (selectRecord.calculateMatchPriority(plugin) == Integer.MAX_VALUE && (selectRecord.state == StubProcessState.STATE_ALLOCATED || selectRecord.state == StubProcessState.STATE_RUNNING))
{
return selectRecord.index;
}
selectRecord.resetAllocate(plugin, processes);
return selectRecord.index;
}
}
private static final int lookupPluginProcess(List<ActivityManager.RunningAppProcessInfo> processes, int index) {
for (ActivityManager.RunningAppProcessInfo pi : processes) {
if (pi.uid != PluginManager.sUid) {
continue;
}
int i = PluginManager.evalPluginProcess(pi.processName);
if (i == index) {
return pi.pid;
}
}
return -1;
}
private static final void waitKilled(int pid) {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100, 0);
} catch (Throwable e) {
//
}
//
List<ActivityManager.RunningAppProcessInfo> processes = AMSUtils.getRunningAppProcessesNoThrows(RePluginInternal.getAppContext());
if (processes == null || processes.isEmpty()) {
continue;
}
boolean found = false;
for (ActivityManager.RunningAppProcessInfo info : processes) {
if (info.pid == pid) {
found = true;
}
}
if (!found) {
return;
}
}
}
static final void cancelPluginProcessLoop() {
if (Constant.SIMPLE_QUIT_CONTROLLER) {
Tasks.cancelThreadTask(CHECK);
}
}
/**
* @param pid
* @param index
* @param plugin
* @param activity
* @param container
* @return
*/
static final boolean attachActivity(int pid, int index, String plugin, String activity, String container) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "reg activity: pid=" + pid + " index=" + index + " plugin=" + plugin + " activity=" + activity + " container=" + container);
}
if (index < 0 || index >= STUB_PROCESSES.length) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "reg activity: invalid index=" + index);
}
return false;
}
ProcessRecord r = STUB_PROCESSES[index];
synchronized (r){
r.activities++;
r.mobified = System.currentTimeMillis();
if (LOG) {
LogDebug.d(PLUGIN_TAG, "activities=" + r.activities + " services=" + r.services + " binders=" + r.binders);
}
}
cancelPluginProcessLoop();
return true;
}
/**
* @param pid
* @param index
* @param plugin
* @param activity
* @param container
* @return
*/
static final boolean detachActivity(int pid, int index, String plugin, String activity, String container) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "unreg activity: pid=" + pid + " index=" + index + " plugin=" + plugin + " activity=" + activity + " container=" + container);
}
if (index < 0 || index >= STUB_PROCESSES.length) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "unreg activity: invalid index=" + index);
}
return false;
}
ProcessRecord r = STUB_PROCESSES[index];
synchronized (r){
r.activities--;
r.mobified = System.currentTimeMillis();
if (LOG) {
LogDebug.d(PLUGIN_TAG, "activities=" + r.activities + " services=" + r.services + " binders=" + r.binders);
}
}
schedulePluginProcessLoop(CHECK_STAGE2_DELAY);
return true;
}
/**
* @param pid
* @param index
* @param plugin
* @param service
* @return
*/
static final boolean attachService(int pid, int index, String plugin, String service) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "reg service: pid=" + pid + " index=" + index + " plugin=" + plugin + " service=" + service);
}
if (index < 0 || index >= STUB_PROCESSES.length) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "reg service: invalid index=" + index);
}
return false;
}
ProcessRecord r = STUB_PROCESSES[index];
synchronized (r) {
r.services++;
r.mobified = System.currentTimeMillis();
if (LOG) {
LogDebug.d(PLUGIN_TAG, "activities=" + r.activities + " services=" + r.services + " binders=" + r.binders);
}
}
cancelPluginProcessLoop();
return true;
}
/**
* @param pid
* @param index
* @param plugin
* @param service
* @return
*/
static final boolean detachService(int pid, int index, String plugin, String service) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "unreg service: pid=" + pid + " index=" + index + " plugin=" + plugin + " service=" + service);
}
if (index < 0 || index >= STUB_PROCESSES.length) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "unreg service: invalid index=" + index);
}
return false;
}
ProcessRecord r = STUB_PROCESSES[index];
synchronized (r){
r.services--;
r.mobified = System.currentTimeMillis();
if (LOG) {
LogDebug.d(PLUGIN_TAG, "activities=" + r.activities + " services=" + r.services + " binders=" + r.binders);
}
}
schedulePluginProcessLoop(CHECK_STAGE2_DELAY);
return true;
}
static final void attachBinder(int pid, IBinder binder) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "reg binder: pid=" + pid + " binder=" + binder);
}
for (ProcessRecord r : STUB_PROCESSES) {
if (r.pid == pid) {
synchronized (r) {
r.binders++;
r.mobified = System.currentTimeMillis();
if (LOG) {
LogDebug.d(PLUGIN_TAG, "activities=" + r.activities + " services=" + r.services + " binders=" + r.binders);
}
}
break;
}
}
cancelPluginProcessLoop();
}
static final void detachBinder(int pid, IBinder binder) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "unreg binder: pid=" + pid + " binder=" + binder);
}
for (ProcessRecord r : STUB_PROCESSES) {
if (r.pid == pid) {
synchronized (r){
r.binders--;
r.mobified = System.currentTimeMillis();
if (LOG) {
LogDebug.d(PLUGIN_TAG, "activities=" + r.activities + " services=" + r.services + " binders=" + r.binders);
}
}
break;
}
}
schedulePluginProcessLoop(CHECK_STAGE2_DELAY);
}
static final int sumBinders(int index) {
if (index >=0 && index < STUB_PROCESSES.length){
ProcessRecord r = STUB_PROCESSES[index];
synchronized (r) {
return STUB_PROCESSES[index].binders;
}
}
return -1;
}
/**
* attach坑位进程设置坑位进程为运行状态并返回正在使用坑位进程的插件名称 buyuntao
*
* @param pid
* @param index
* @param binder
* @param client
* @param def
* @return
*/
static final String attachStubProcess(int pid, int index, IBinder binder, IPluginClient client, String def) {
// 检测状态是否一致
ProcessRecord r = STUB_PROCESSES[index];
synchronized (r) {
if (!TextUtils.isEmpty(def)) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "attach process: allocate now");
}
r.allocate(def);
}
if (r.state != StubProcessState.STATE_ALLOCATED) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "attach process: state not allocated: state=" + r.state);
}
return null;
}
r.setRunning(pid);
r.setClient(binder, client);
return r.plugin;
}
}
static final void setProcessStop(final IBinder binder) {
for (ProcessRecord r : STUB_PROCESSES) {
synchronized (r) {
if (r.binder == binder) {
r.setStoped();
break;
}
}
}
}
private static final void doPluginProcessLoop() {
if (Constant.SIMPLE_QUIT_CONTROLLER) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "do plugin process quit check");
}
for (ProcessRecord r : STUB_PROCESSES) {
synchronized (r) {
if (r.state != StubProcessState.STATE_RUNNING) {
continue;
}
if (r.activities > 0) {
continue;
}
if (r.services > 0) {
continue;
}
if (r.binders > 0) {
continue;
}
if (LOGR) {
// terminate empty process
LogRelease.i(PLUGIN_TAG, "t e p " + r.pid);
}
//
android.os.Process.killProcess(r.pid);
waitKilled(r.pid);
r.setStoped();
//
schedulePluginProcessLoop(CHECK_STAGE3_DELAY);
return;
}
}
}
}
static final void schedulePluginProcessLoop(long delayMillis) {
if (Constant.SIMPLE_QUIT_CONTROLLER) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "schedule plugin process quit check: delay=" + (delayMillis / 1000));
}
Tasks.cancelThreadTask(CHECK);
Tasks.postDelayed2Thread(CHECK, delayMillis);
}
}
static final void dump(PrintWriter writer) {
writer.println("--- STUB_PROCESSES.length = " + STUB_PROCESSES.length + " ---");
for (ProcessRecord r : STUB_PROCESSES) {
synchronized (r){
writer.println(r);
}
}
}
/**
* 坑位进程的状态 buyuntao
*/
public class StubProcessState {
public static final int STATE_UNUSED = 0;
public static final int STATE_ALLOCATED = 1;
public static final int STATE_RUNNING = 2;
public static final int STATE_STOPED = 4;
}
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 = StubProcessState.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 = StubProcessState.STATE_RUNNING;
this.pid = pid;
}
void setClient(IBinder binder, IPluginClient client) {
this.binder = binder;
this.client = client;
}
void setStoped() {
this.state = StubProcessState.STATE_STOPED;
this.pid = 0;
this.binder = null;
this.client = null;
}
/**
* 当前坑位的选择优先级值越大被选中的概率越高
*
* @param newPluginName
* @return 坑位的选择优先级
*/
int calculateMatchPriority(String newPluginName) {
int priority = Integer.MAX_VALUE;
if (TextUtils.equals(newPluginName, plugin)) { //插件可能用过的进程
return priority;
}
if (state == StubProcessState.STATE_UNUSED) { //空闲的进程
priority = Integer.MAX_VALUE - 1;
return priority;
}
if (state == StubProcessState.STATE_STOPED) { //已停止的进程
priority = Integer.MAX_VALUE - 2;
return priority;
}
if ((System.currentTimeMillis() - mobified) > 10 * 1000) { //分配时间超过10秒的
priority = Integer.MAX_VALUE - 3;
return priority;
}
if ((activities <= 0) && (services <= 0) && (binders <= 0)) { //组件为空的
priority = Integer.MAX_VALUE - 4;
return priority;
}
priority = 0; //默认值
return priority;
}
void resetAllocate(String plugin, List<ActivityManager.RunningAppProcessInfo> processes) {
killProcess(processes);
allocate(plugin);
}
private void killProcess(List<ActivityManager.RunningAppProcessInfo> processes) {
// 确保进程为空
int pid = lookupPluginProcess(processes, index);
if (pid > 0) {
if (LOGR) {
LogRelease.i(PLUGIN_TAG, "ppr k i: " + pid);
}
android.os.Process.killProcess(pid);
waitKilled(pid);
}
}
@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();
}
}
}

View File

@ -66,6 +66,7 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.qihoo360.replugin.helper.LogDebug.LOG;
@ -915,6 +916,8 @@ public class RePlugin {
static boolean sAttached;
static AtomicBoolean sCreated = new AtomicBoolean(false);
/**
* 当Application的attachBaseContext调用时需调用此方法 <p>
* 使用插件框架默认的方案
@ -997,6 +1000,10 @@ public class RePlugin {
throw new IllegalStateException();
}
if (!sCreated.compareAndSet(false, true)) {
return;
}
Tasks.init();
PMF.callAppCreate();