Программное выполнение команды adb shell dpm в приложении приводит к невозможности запуска программы adb: ошибка = 13, разрешение отклонено

Я пытаюсь выполнить следующую команду:

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

и получили следующее исключение

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)

Я пытаюсь установить свое устройство в качестве владельца, программно выполнив «adb shell dpm set-device-owner com.example.package/.DeviceAdmin».

Я имел в виду следующие ссылки SO, однако я не могу избавиться от этой ошибки.

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

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

ПРИМЕЧАНИЕ. Я пытался запустить команду без префикса оболочки adb, однако она возвращала значение null и не применяла никаких изменений.

Следующий код выполняет мою команду.

     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();
        }

Ниже мой подкласс DeviceAdminReceiver

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");
}

}

Мой манифест, регистрирующий мой приемник

 <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>

Проверены настройки и устройство не имеет учетных записей (это устройство Android без каких-либо сервисов Google Play и не имеет root-прав). Приложение имеет minSdkVersion 21/targetSdkVersion 27.

В конечном счете, я хочу установить устройство в качестве владельца (без NFC) с единственной целью — закрепить экран, не спрашивая разрешения пользователя (это POS-приложение). Как я могу выполнить команду, чтобы установить устройство в качестве владельца без каких-либо исключений?


person Eugenio Lopez    schedule 06.10.2018    source источник


Ответы (2)


Я пытаюсь установить свое устройство в качестве владельца программно

Существует только два законных способа сделать приложение владельцем устройства.

а) Подготовка устройства

После распаковки устройства вы касаетесь его специально подготовленной меткой NFC. Приложение, указанное в инструкциях, хранящихся в метке NFC, теперь назначается владельцем устройства.

б) АБР

Вы можете использовать команду, упомянутую в вопросе, если выполняются следующие условия:

  • Владелец устройства не указан
  • На устройстве не зарегистрированы учетные записи

Команду dpm set-device-owner можно запустить только из оболочки, открытой пользователем (т. е. ADB с компьютера разработчика). Она не работает с оболочкой, открытой Runtime.exec(). И, очевидно, даже если бы вы могли ADB с устройства на себя, оно попало бы под те же ограничения.

Источник:

В конечном счете, я хочу установить устройство в качестве владельца (без NFC) с единственной целью — закрепить экран, не спрашивая разрешения пользователя.

Вы можете использовать скрытый системный API (android.app.StatusBarManager), чтобы самостоятельно скрыть строку состояния и кнопки навигации и подписать ваше приложение подписью платформы производителем устройства. Вам понадобится подпись для разрешения android.permission.STATUS_BAR.

person Eugen Pechanec    schedule 06.10.2018
comment
Спасибо за публикацию. Сообщения SO (на которые я ссылался) меня немного смутили, поскольку они изображают возможность выполнять точную команду времени выполнения, как и я. Может ли это быть потому, что они работают на корневом устройстве? - person Eugenio Lopez; 09.10.2018
comment
ADB с машины разработчика действительно был единственным способом запустить команду. Я также уверен, что ссылки, которые я привел, были для рутированных устройств. - person Eugenio Lopez; 06.12.2018

Короткий ответ: ваше приложение не может выполнять команды ADB. Это было бы огромной дырой в безопасности для Android.

Если вы хотите программно настроить свое устройство в качестве администратора устройства, взгляните на пример на документация

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);
person Nick Cardoso    schedule 06.10.2018
comment
Спасибо за публикацию. Да, я пробовал это выше, однако он возвращает false для devicePolicyManager.isDeviceOwnerApp(); Как вы упомянули, приведенное выше устанавливает только администратора устройства, а не владельца устройства. Будет ли лучше удаление префикса оболочки adb? Я немного смущен, так как вижу, что эта команда, по-видимому, работает над ссылками SO, которые я разместил. - person Eugenio Lopez; 06.10.2018
comment
Когда devicePolicyManager.isDeviceOwnerApp() возвращает false? Я не вижу проверки в примере кода в вашем вопросе - person Nick Cardoso; 06.10.2018
comment
Запуск намерения был моим первоначальным подходом, но я удалил его, поскольку он предназначался только для администратора устройства. Как я это сделал, после того, как пользователь выбрал активацию для намерения, в моем onActivityResult(), если результат был в порядке, я бы проверил devicePolicyManager.isDeviceOwnerApp(), и он вернул бы false. Однако devicePolicyManager.isAdminActive() возвращает true, что по-прежнему не позволяет мне достичь моей цели по закреплению экрана без разрешения пользователя. - person Eugenio Lopez; 06.10.2018