需求不讲了,目的是当app收到广播时,需要获取到发送者的包名(及pid、uid)。
关键字:onReceive、ComponetName、broadcasts、adb shell dumpsys activity broadcasts
一般来讲,通过如下方法,只是获取到当前的报名而非发送者包名,并非期望结果:
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "---onReceive: " + intent.getComponent() == null ? "null" : intent.getComponent().getPackageName());
}
发送广播原理,不在重复介绍,可以参考现有文章:Broadcast机制源码详解-处理
从源码角度看,在发送广播初始阶段,会存储广播相关信息,这里就包括发送广播的应用报名,进程等。mMainThread.getApplicationThread()
,在后面逻辑,会通过进程号来获取到报名。activityThread里都有这些信息可查。
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
//1. 返回 intent的 MIME data type
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess();
//2.直接调用ams的方法.
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
getUserId());
} catch (RemoteException e) {
}
}
这里就是说一下,广播和发送者的包名都是关联的,在broadcastrecord里都有存储。
知道ams有很多信息都可以通过adb shell dumpsys获取到,广播的信息也不例外。
输入:adb shell dumpsys activity broadcasts|grep -iE "com.example.broadcast|caller="
这里接受的是另一个demo app里发送的com.example.broadcast广播。通过信息可以看到,确实包含了发送者的信息:
从代码角度获取BroadcastQueue.java
中的mBroadcastHistory
不太现实。
/**
108 * Historical data of past broadcasts, for debugging. This is a ring buffer
109 * whose last element is at mHistoryNext.
110 */
111 final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
112 int mHistoryNext = 0;
所以通过代码执行adb语句,然后通过输出,过滤拿到发送者包名。其中执行安卓执行adb语句参考文章:安卓代码 实现 adb功能/shell语句/dumpsys等
代码如下:
@Override
public void onReceive(Context context, Intent intent) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
exec("dumpsys activity broadcasts");
}
});
thread.start();
}
private static String exec(String command) {
Process process = null;
try {
process = Runtime.getRuntime().exec(command);
} catch (IOException ex) {
ex.printStackTrace();
} //adb shell
// final BufferedWriter outputStream = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
final BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream()));
//这里一定要注意错误流的读取,不然很容易阻塞,得不到你想要的结果,
final BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
final Process finalProcess = process;
new Thread(new Runnable() {
public void run() {
String line;
boolean castFlag = false;
String[] info;
try {
while ((line = inputStream.readLine()) != null) {
if (line.contains(ACTIONTAG)) {
castFlag = line.contains(CAST);
}
if (castFlag && line.contains(CALLERTAG)) {
line = line.trim();
info = line.split(" ");
for (String i: info)
Log.d(TAG, "run: " + i);
Log.d(TAG, "packageName: " + info[0].substring(CALLERTAG.length()));
finalProcess.destroy();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
try {
process.waitFor();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return null;
}
整体源码在github。其中只关注MyReciver类即可。其他类为其他需求实现demo。