Skip to content

Commit 7d4a2e1

Browse files
authoredAug 29, 2017
Merge pull request #318 from cundong/dev
Support detail runtime info dump
2 parents f050f5c + 11c3654 commit 7d4a2e1

File tree

12 files changed

+328
-32
lines changed

12 files changed

+328
-32
lines changed
 

‎replugin-host-library/replugin-host-lib/src/main/aidl/com/qihoo360/loader2/IPluginClient.aidl

+11-1
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,14 @@ interface IPluginClient {
3131
* @param Intent 广播的 Intent 数据
3232
*/
3333
void onReceive(String plugin, String receiver, in Intent intent);
34-
}
34+
35+
/**
36+
* dump通过插件化框架启动起来的Service信息
37+
*/
38+
String dumpServices();
39+
40+
/**
41+
* dump插件化框架中存储的详细Activity坑位映射表
42+
*/
43+
String dumpActivities();
44+
}

‎replugin-host-library/replugin-host-lib/src/main/aidl/com/qihoo360/loader2/IPluginHost.aidl

+6-1
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,9 @@ interface IPluginHost {
109109
* 通过PID来获取进程名
110110
*/
111111
String getProcessNameByPid(int pid);
112-
}
112+
113+
/**
114+
* dump详细的运行时信息
115+
*/
116+
String dump();
117+
}

‎replugin-host-library/replugin-host-lib/src/main/aidl/com/qihoo360/replugin/component/service/server/IPluginServiceServer.aidl

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@ interface IPluginServiceServer {
1717

1818
int bindService(in Intent intent, in IServiceConnection conn, int flags, in Messenger client);
1919
boolean unbindService(in IServiceConnection conn);
20-
}
20+
21+
String dump();
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (C) 2005-2017 Qihoo 360 Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed To in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package com.qihoo360.loader2;
18+
19+
import android.os.IBinder;
20+
import android.util.Log;
21+
22+
import com.qihoo360.replugin.RePluginInternal;
23+
24+
import java.io.FileDescriptor;
25+
import java.io.PrintWriter;
26+
27+
/**
28+
* 运行时 dump 工具类
29+
*
30+
* @author RePlugin Team
31+
*/
32+
public class DumpUtils {
33+
34+
private static final String TAG = RePluginInternal.FOR_DEV ? DumpUtils.class.getSimpleName() : "DumpUtils";
35+
36+
/**
37+
* dump RePlugin框架运行时的详细信息,包括:Activity 坑位映射表,正在运行的 Service,以及详细的插件信息
38+
*
39+
* @param fd
40+
* @param writer
41+
* @param args
42+
*/
43+
public static void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
44+
45+
IBinder binder = PluginProviderStub.proxyFetchHostBinder(RePluginInternal.getAppContext());
46+
47+
if (binder == null) {
48+
return;
49+
}
50+
51+
IPluginHost pluginHost = IPluginHost.Stub.asInterface(binder);
52+
53+
try {
54+
String dumpInfo = pluginHost.dump();
55+
56+
if (RePluginInternal.FOR_DEV) {
57+
Log.d(TAG, "dumpInfo:" + dumpInfo);
58+
}
59+
60+
if (writer != null) {
61+
writer.println(dumpInfo);
62+
}
63+
} catch (Throwable e) {
64+
e.printStackTrace();
65+
}
66+
}
67+
}

‎replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/PluginContainers.java

+30-1
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,13 @@
2727
import com.qihoo360.replugin.base.IPC;
2828
import com.qihoo360.replugin.component.process.PluginProcessHost;
2929
import com.qihoo360.replugin.helper.HostConfigHelper;
30+
import com.qihoo360.replugin.helper.JSONHelper;
3031
import com.qihoo360.replugin.helper.LogDebug;
3132
import com.qihoo360.replugin.helper.LogRelease;
3233

34+
import org.json.JSONArray;
35+
import org.json.JSONObject;
36+
3337
import java.lang.ref.WeakReference;
3438
import java.util.ArrayList;
3539
import java.util.HashMap;
@@ -41,6 +45,7 @@
4145
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
4246
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
4347
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
48+
import static com.qihoo360.loader2.PluginContainers.ActivityState.toName;
4449
import static com.qihoo360.replugin.helper.LogDebug.LOG;
4550
import static com.qihoo360.replugin.helper.LogDebug.PLUGIN_TAG;
4651
import static com.qihoo360.replugin.helper.LogRelease.LOGR;
@@ -771,4 +776,28 @@ final ActivityState lookupByContainer(String container) {
771776

772777
return null;
773778
}
774-
}
779+
780+
final String dump() {
781+
782+
JSONArray activityArr = new JSONArray();
783+
JSONObject activityObj;
784+
785+
for (Map.Entry<String, ActivityState> entry : mStates.entrySet()) {
786+
String container = entry.getKey();
787+
ActivityState state = entry.getValue();
788+
789+
if (!TextUtils.isEmpty(state.plugin) && !TextUtils.isEmpty(state.activity)) {
790+
activityObj = new JSONObject();
791+
JSONHelper.putNoThrows(activityObj, "process", IPC.getCurrentProcessName());
792+
JSONHelper.putNoThrows(activityObj, "className", container);
793+
JSONHelper.putNoThrows(activityObj, "plugin", state.plugin);
794+
JSONHelper.putNoThrows(activityObj, "realClassName", state.activity);
795+
JSONHelper.putNoThrows(activityObj, "state", toName(state.state));
796+
JSONHelper.putNoThrows(activityObj, "refs", state.refs != null ? state.refs.size() : 0);
797+
activityArr.put(activityObj);
798+
}
799+
}
800+
801+
return activityArr.toString();
802+
}
803+
}

‎replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/PluginProcessMain.java

+71
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
import com.qihoo360.replugin.packages.PluginManagerProxy;
3636
import com.qihoo360.replugin.packages.PluginManagerServer;
3737

38+
import org.json.JSONArray;
39+
import org.json.JSONException;
40+
import org.json.JSONObject;
41+
3842
import java.io.FileDescriptor;
3943
import java.io.PrintWriter;
4044
import java.util.HashMap;
@@ -229,6 +233,10 @@ public String toString() {
229233
}
230234
return super.toString();
231235
}
236+
237+
public IPluginClient getClient() {
238+
return client;
239+
}
232240
}
233241

234242
static final void reportStatus() {
@@ -242,6 +250,69 @@ static final void reportStatus() {
242250
}
243251
}
244252

253+
static final String dump() {
254+
255+
// 1.dump Activity映射表, service列表
256+
JSONArray activityArr = new JSONArray();
257+
JSONArray serviceArr = new JSONArray();
258+
259+
for (ProcessClientRecord clientRecord : ALL.values()) {
260+
try {
261+
IPluginClient pluginClient = clientRecord.getClient();
262+
if (pluginClient == null) {
263+
continue;
264+
}
265+
266+
String activityDumpInfo = pluginClient.dumpActivities();
267+
JSONArray activityList = new JSONArray(activityDumpInfo);
268+
int activityCount = activityList.length();
269+
if (activityCount > 0) {
270+
for (int i = 0; i < activityCount; i++) {
271+
activityArr.put(activityList.getJSONObject(i));
272+
}
273+
}
274+
275+
String serviceDumpInfo = pluginClient.dumpServices();
276+
JSONArray serviceList = new JSONArray(serviceDumpInfo);
277+
int serviceCount = serviceList.length();
278+
if (serviceCount > 0) {
279+
for (int i = 0; i < serviceCount; i++) {
280+
serviceArr.put(serviceList.getJSONObject(i));
281+
}
282+
}
283+
} catch (Throwable e) {
284+
e.printStackTrace();
285+
}
286+
}
287+
288+
// 2.dump 插件信息表
289+
JSONArray pluginArr = new JSONArray();
290+
List<PluginInfo> pluginList = MP.getPlugins(false);
291+
if (pluginList != null) {
292+
JSONObject pluginObj;
293+
for (PluginInfo pluginInfo : pluginList) {
294+
try {
295+
pluginObj = new JSONObject();
296+
pluginObj.put(pluginInfo.getName(), pluginInfo.toString());
297+
pluginArr.put(pluginObj);
298+
} catch (JSONException e) {
299+
e.printStackTrace();
300+
}
301+
}
302+
}
303+
304+
JSONObject detailObj = new JSONObject();
305+
try {
306+
detailObj.put("activity", activityArr);
307+
detailObj.put("service", serviceArr);
308+
detailObj.put("plugin", pluginArr);
309+
} catch (JSONException e) {
310+
e.printStackTrace();
311+
}
312+
313+
return detailObj.toString();
314+
}
315+
245316
static final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
246317
if (LogDebug.DUMP_ENABLED) {
247318
writer.println("--- ALL.length = " + ALL.size() + " ---");

‎replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/PluginProcessPer.java

+26-1
Original file line numberDiff line numberDiff line change
@@ -330,4 +330,29 @@ final String bindActivity(String plugin, int process, String activity, Intent in
330330
public void onReceive(String plugin, final String receiver, final Intent intent) {
331331
PluginReceiverHelper.onPluginReceiverReceived(plugin, receiver, mReceivers, intent);
332332
}
333-
}
333+
334+
@Override
335+
public String dumpServices() {
336+
try {
337+
IPluginServiceServer pss = fetchServiceServer();
338+
if (pss != null) {
339+
try {
340+
return pss.dump();
341+
} catch (Throwable e) {
342+
if (LOGR) {
343+
LogRelease.e(PLUGIN_TAG, "psc.sts: pss e", e);
344+
}
345+
}
346+
}
347+
} catch (RemoteException e) {
348+
e.printStackTrace();
349+
}
350+
351+
return null;
352+
}
353+
354+
@Override
355+
public String dumpActivities() {
356+
return mACM.dump();
357+
}
358+
}

‎replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/PmHostSvc.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -621,4 +621,9 @@ public int getPidByProcessName(String processName) throws RemoteException {
621621
public String getProcessNameByPid(int pid) throws RemoteException {
622622
return PluginProcessMain.getProcessNameByPid(pid);
623623
}
624-
}
624+
625+
@Override
626+
public String dump() {
627+
return PluginProcessMain.dump();
628+
}
629+
}

‎replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/replugin/component/service/server/PluginServiceServer.java

+64-16
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,24 @@
3131
import com.qihoo360.i.Factory;
3232
import com.qihoo360.loader2.mgr.IServiceConnection;
3333
import com.qihoo360.mobilesafe.core.BuildConfig;
34-
import com.qihoo360.replugin.utils.basic.ArrayMap;
3534
import com.qihoo360.replugin.RePlugin;
3635
import com.qihoo360.replugin.base.IPC;
3736
import com.qihoo360.replugin.base.ThreadUtils;
3837
import com.qihoo360.replugin.component.ComponentList;
3938
import com.qihoo360.replugin.component.utils.PluginClientHelper;
39+
import com.qihoo360.replugin.helper.JSONHelper;
4040
import com.qihoo360.replugin.helper.LogDebug;
4141
import com.qihoo360.replugin.helper.LogRelease;
42+
import com.qihoo360.replugin.utils.basic.ArrayMap;
43+
44+
import org.json.JSONArray;
45+
import org.json.JSONObject;
4246

4347
import java.lang.reflect.Field;
4448
import java.lang.reflect.InvocationTargetException;
4549
import java.lang.reflect.Method;
4650
import java.util.ArrayList;
51+
import java.util.Map;
4752
import java.util.concurrent.Callable;
4853

4954
import static com.qihoo360.replugin.helper.LogDebug.LOG;
@@ -422,7 +427,9 @@ private boolean installServiceLocked(ServiceRecord sr) {
422427
sr.service = s;
423428

424429
// 开启“坑位”服务,防止进程被杀
425-
startPitService();
430+
ComponentName pitCN = getPitComponentName();
431+
sr.pitComponentName = pitCN;
432+
startPitService(pitCN);
426433
return true;
427434
}
428435

@@ -487,7 +494,9 @@ private void recycleServiceLocked(ServiceRecord r) {
487494
r.service.onDestroy();
488495

489496
// 停止“坑位”服务,系统可以根据需要来回收了
490-
stopPitService();
497+
ComponentName pitCN = getPitComponentName();
498+
r.pitComponentName = pitCN;
499+
stopPitService(pitCN);
491500
}
492501

493502
// 通过反射调用Service.attachBaseContext方法(Protected的)
@@ -535,6 +544,13 @@ public boolean unbindService(IServiceConnection conn) throws RemoteException {
535544
return PluginServiceServer.this.unbindServiceLocked(conn);
536545
}
537546
}
547+
548+
@Override
549+
public String dump() throws RemoteException {
550+
synchronized (LOCKER) {
551+
return PluginServiceServer.this.dump();
552+
}
553+
}
538554
}
539555

540556
// 通过Client端传来的IBinder(Messenger)来获取Pid,以及进程信息
@@ -548,19 +564,24 @@ private ProcessRecord retrieveProcessRecordLocked(Messenger client) {
548564
return pr;
549565
}
550566

551-
// 开启“坑位”服务,防止进程被杀
552-
private void startPitService() {
553-
// TODO 其实,有一种更好的办法……敬请期待
567+
// 构建一个占坑服务
568+
private ComponentName getPitComponentName() {
554569
String pname = IPC.getCurrentProcessName();
555570
int process = PluginClientHelper.getProcessInt(pname);
556571

557-
ComponentName cn = PluginPitService.makeComponentName(mContext, process);
572+
return PluginPitService.makeComponentName(mContext, process);
573+
}
574+
575+
// 开启“坑位”服务,防止进程被杀
576+
private void startPitService(ComponentName pitCN) {
577+
// TODO 其实,有一种更好的办法……敬请期待
578+
558579
if (LOG) {
559-
LogDebug.d(TAG, "startPitService: Start " + cn);
580+
LogDebug.d(TAG, "startPitService: Start " + pitCN);
560581
}
561582

562583
Intent intent = new Intent();
563-
intent.setComponent(cn);
584+
intent.setComponent(pitCN);
564585

565586
try {
566587
mContext.startService(intent);
@@ -571,17 +592,14 @@ private void startPitService() {
571592
}
572593

573594
// 停止“坑位”服务,系统可以根据需要来回收了
574-
private void stopPitService() {
575-
String pname = IPC.getCurrentProcessName();
576-
int process = PluginClientHelper.getProcessInt(pname);
595+
private void stopPitService(ComponentName pitCN) {
577596

578-
ComponentName cn = PluginPitService.makeComponentName(mContext, process);
579597
if (LOG) {
580-
LogDebug.d(TAG, "stopPitService: Stop " + cn);
598+
LogDebug.d(TAG, "stopPitService: Stop " + pitCN);
581599
}
582600

583601
Intent intent = new Intent();
584-
intent.setComponent(cn);
602+
intent.setComponent(pitCN);
585603
try {
586604
mContext.stopService(intent);
587605
} catch (Exception e) {
@@ -590,4 +608,34 @@ private void stopPitService() {
590608
}
591609
}
592610

593-
}
611+
/**
612+
* dump当前进程中运行的service详细信息,供client端使用
613+
*
614+
* @return
615+
*/
616+
private String dump() {
617+
618+
if (mServicesByName == null || mServicesByName.isEmpty()) {
619+
return null;
620+
}
621+
622+
JSONArray jsonArray = new JSONArray();
623+
624+
JSONObject serviceObj;
625+
for (Map.Entry<ComponentName, ServiceRecord> entry : mServicesByName.entrySet()) {
626+
ComponentName key = entry.getKey();
627+
ServiceRecord value = entry.getValue();
628+
629+
serviceObj = new JSONObject();
630+
631+
JSONHelper.putNoThrows(serviceObj, "className", key.getClassName());
632+
JSONHelper.putNoThrows(serviceObj, "process", value.getServiceInfo().processName);
633+
JSONHelper.putNoThrows(serviceObj, "plugin", value.getPlugin());
634+
JSONHelper.putNoThrows(serviceObj, "pitClassName", value.getPitComponentName().getClassName());
635+
636+
jsonArray.put(serviceObj);
637+
}
638+
639+
return jsonArray.toString();
640+
}
641+
}

‎replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/replugin/component/service/server/ServiceRecord.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ class ServiceRecord {
5454
// Service对象
5555
Service service;
5656

57+
// 替当前 "插件服务" 在AMS中占坑的组件
58+
ComponentName pitComponentName;
59+
5760
// 是否调用过startService且没有停止
5861
boolean startRequested;
5962

@@ -109,4 +112,16 @@ public boolean hasAutoCreateConnections() {
109112
public String toString() {
110113
return "[srv=" + service.getClass().getName() + "; startRequested=" + startRequested + "; bindings=(" + bindings.size() + ") " + bindings + "]";
111114
}
112-
}
115+
116+
public String getPlugin() {
117+
return plugin;
118+
}
119+
120+
public ComponentName getPitComponentName() {
121+
return pitComponentName;
122+
}
123+
124+
public ServiceInfo getServiceInfo() {
125+
return serviceInfo;
126+
}
127+
}

‎replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/replugin/model/PluginInfo.java

+27-8
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import android.content.pm.PackageInfo;
2323
import android.database.Cursor;
2424
import android.database.MatrixCursor;
25-
import android.os.Build;
2625
import android.os.Bundle;
2726
import android.os.Parcel;
2827
import android.os.Parcelable;
@@ -42,6 +41,7 @@
4241
import org.json.JSONObject;
4342

4443
import java.io.File;
44+
import java.util.Arrays;
4545
import java.util.Comparator;
4646
import java.util.regex.MatchResult;
4747
import java.util.regex.Matcher;
@@ -848,14 +848,15 @@ private void toContentString(StringBuilder b) {
848848
b.append("[DEX_EXTRACTED] ");
849849
}
850850

851-
// 插件是否“已被使用”
852-
if (RePlugin.isPluginUsed(getName())) {
853-
b.append("[USED] ");
854-
}
855-
856851
// 插件是否“正在使用”
857852
if (RePlugin.isPluginRunning(getName())) {
858-
b.append("[USING] ");
853+
b.append("[RUNNING] ");
854+
}
855+
856+
// 哪些进程使用
857+
String[] processes = RePlugin.getRunningProcessesByPlugin(getName());
858+
if (processes != null) {
859+
b.append("processes=").append(Arrays.toString(processes)).append(' ');
859860
}
860861

861862
// 插件基本信息
@@ -877,7 +878,25 @@ public int hashCode() {
877878

878879
@Override
879880
public boolean equals(Object obj) {
880-
return mJson.equals(obj);
881+
if (obj == null) {
882+
return false;
883+
}
884+
885+
if (this == obj) {
886+
return true;
887+
}
888+
889+
if (this.getClass() != obj.getClass()) {
890+
return false;
891+
}
892+
893+
PluginInfo pluginInfo = (PluginInfo) obj;
894+
895+
try {
896+
return pluginInfo.mJson.equals(mJson);
897+
} catch (Exception e) {
898+
return false;
899+
}
881900
}
882901

883902

‎replugin-sample/host/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ buildscript {
2020
}
2121
dependencies {
2222
classpath 'com.android.tools.build:gradle:2.3.3'
23-
classpath 'com.qihoo360.replugin:replugin-host-gradle:2.1.7'
23+
classpath 'com.qihoo360.replugin:replugin-host-gradle:2.2.0'
2424
}
2525
}
2626

0 commit comments

Comments
 (0)
Please sign in to comment.