javaandroidandroid-intent

Why does intent.getStringExtra() return null when broadcast is sent using "am" shell command?


I have an app that runs as UID 1000 (system), and I want to run shell commands as the system user via this app and display the output as a toast.

CmdReceiver.java:

package com.ishacker.android.cmdreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Objects;

public class CmdReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String Cmd = intent.getStringExtra("Cmd");
        try {
            Process process = Runtime.getRuntime().exec(Cmd);
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()));

            int read;
            char[] buffer = new char[4096];
            StringBuffer output = new StringBuffer();
            while ((read = reader.read(buffer)) > 0) {
                output.append(buffer, 0, read);
            }
            reader.close();
            process.waitFor();
            if (!Objects.equals(intent.getStringExtra("App"), "yes")) {
                Toast.makeText(context, output.toString(), Toast.LENGTH_LONG).show();
            }
            else {
                // Code to handle what happens when it is launched using intent.putExtra("App","yes")
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:sharedUserId="android.uid.system" >
        <receiver android:name=".CmdReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

This is the command I used to broadcast:

am broadcast com.ishacker.android.cmdreceiver/.CmdReceiver --es Cmd "whoami"

Apparently intent.getStringExtra("Cmd") always returns null for some reason.

Is there anything wrong in my code or the command used to broadcast?


Solution

  • Try this command:

    am broadcast -n com.ishacker.android.cmdreceiver/.CmdReceiver --es Cmd "whoami"
    

    The -n flag specifies the component name explicitly. Without it, the broadcast may not be delivered correctly to the receiver, and trying to get extras with intent.getStringExtra() will result in it returning null.

    Without it, the broadcast may not be delivered correctly to your receiver