javaandroidandroid-studioruntime.execdevice-policy-manager

programmatically executing adb shell dpm command within app yields Cannot run program "adb": error=13, Permission denied


I'm trying to execute the following command :

Process process = Runtime.getRuntime().exec("adb shell dpm set-device-owner com.example.package/.DeviceAdmin", null,null);

and have gotten the following Exception

W/System.err:java.io.IOException: Cannot run program "adb": error=13, Permission denied
W/System.err: at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
W/System.err: at java.lang.Runtime.exec(Runtime.java:692)
W/System.err: at java.lang.Runtime.exec(Runtime.java:525)

I'm trying to set my device as the owner by programmatically executing "adb shell dpm set-device-owner com.example.package/.DeviceAdmin".

I've been referring to the following SO links however I cant seem to get out this error.

https://stackoverflow.com/a/27909315/5521089

https://stackoverflow.com/a/44164984/5521089

NOTE: I've tried running the command w/o the adb shell prefix, however it was returning null and not applying any changes.

The following code executes my command.

     try {
            StringBuffer output = new StringBuffer();
            Process process = Runtime.getRuntime().exec("dpm set-device-owner com.example.package/.DeviceAdmin", null,null);
            process.waitFor();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

            String line = "";
            while ((line = reader.readLine()) != null) {
               output.append(line + "n");
               Log.d("OUTPUT = ", output.toString());
            }

        } catch (Exception e) {
            Log.e("LOGINACTIVITY ", "device owner not set");
            Log.e("LOGINACTIVITY ", e.toString());
            e.printStackTrace();
        }

Below is my DeviceAdminReceiver subclass

public class DeviceAdmin extends DeviceAdminReceiver {

public ComponentName getComponentName(Context context){
    return new ComponentName(context.getApplicationContext(), DeviceAdmin.class);
}

void showToast(Context context, String msg) {
    String status = msg;
    Toast.makeText(context, status, Toast.LENGTH_SHORT).show();
}

@Override
public void onEnabled(Context context, Intent intent) {
    showToast(context, "Enabled");
}


@Override
public void onDisabled(Context context, Intent intent) {
    showToast(context,"Disabled");
}

}

My Manifest registering my receiver

 <application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <receiver
        android:name=".DeviceAdmin"
        android:permission="android.permission.BIND_DEVICE_ADMIN">
        <meta-data
            android:name="android.app.device_admin"
            android:resource="@xml/policies"/>
        <intent-filter>
            <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
        </intent-filter>
    </receiver>


</application>

Checked settings and device has no accounts(It's an android device without any google play services and is not rooted.). The app has a minSdkVersion of 21/targetSdkVersion of 27.

Ultimately, I wish to set device as owner(without NFC) for the sole purpose of pinning the screen without asking user permission.(it's a POS application). How can I execute the command so that I can set the device as owner without any exceptions?


Solution

  • I'm trying to set my device as the owner by programmatically

    There are only two legit ways an app can be set as device owner.

    a) Device provisioning

    After you unbox a device you tap it with a specially prepared NFC tag. An app specified by instructions stored on the NFC tag is now set as the device owner.

    b) ADB

    You can use the command mentioned in the question as long as these conditions are met:

    The dpm set-device-owner command can only be run from shell that's been opened by the user (i.e. ADB from a dev machine). It doesn't work with a shell opened by Runtime.exec(). And, obviously, even if you could ADB from the device to itself, it would fall under the same restrictions.

    Source:

    Ultimately, I wish to set device as owner(without NFC) for the sole purpose of pinning the screen without asking user permission

    You could use hidden system API (android.app.StatusBarManager) to hide the status bar and navigation buttons yourself and have your app signed with the platform signature by the device manufacturer. You'll need the signature for the android.permission.STATUS_BAR permission.