安卓代码实现:接收到广播后,获取广播发送者包名

需求不讲了,目的是当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广播。通过信息可以看到,确实包含了发送者的信息:
安卓代码实现:接收到广播后,获取广播发送者包名_第1张图片

三、实现

从代码角度获取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。

你可能感兴趣的:(android)