1

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?

0

2 Answers 2

1

The short answer is: Your app cannot run ADB commands. It would be a huge security hole for Android to allow this.

If you want to set your device as Device admin programmatically, take a look at the example on the documentation

Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mDeviceAdminSample);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, getString(R.string.add_admin_extra_app_text));
startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
3
  • Thanks for posting. Yes, I've tried the above, however it returns false for devicePolicyManager.isDeviceOwnerApp(); As you mentioned, the above only only sets the device admin, not device owner. Would removing the adb shell prefix be of any better? I'm a bit confused since i see this command apparently working on the SO links I've posted. Commented Oct 6, 2018 at 19:28
  • When does devicePolicyManager.isDeviceOwnerApp() return false? I can't see a check in the sample code in your question Commented Oct 6, 2018 at 19:29
  • Launching the intent was my original approach but I removed it since it was only for device admin. How I had it was after user selected activate for the intent, within my onActvityResult() if result was okay, i'd check devicePolicyManager.isDeviceOwnerApp() and it would return false. However devicePolicyManager.isAdminActive() returns true, which still does not allow me to achieve my goal of pinning screen w/o user permission. Commented Oct 6, 2018 at 19:39
0

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:

  • There is no device owner set
  • There are no accounts registered on the device

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.

2
  • Thanks for posting. The SO posts(which I've linked) got me a bit confused since they depict being able to execute the exact run-time command as I. Could this be because they're running on a rooted device? Commented Oct 9, 2018 at 16:58
  • ADB from a dev machine was indeed the only way I could run the command. I'm further certain the links I cited were for rooted devices. Commented Dec 6, 2018 at 15:47

Not the answer you're looking for? Browse other questions tagged or ask your own question.