在应用程序中以编程方式执行 adb shell dpm 命令会产生无法运行程序“adb”:错误 = 13,权限被拒绝 [重复]

Posted

技术标签:

【中文标题】在应用程序中以编程方式执行 adb shell dpm 命令会产生无法运行程序“adb”:错误 = 13,权限被拒绝 [重复]【英文标题】:programmatically executing adb shell dpm command within app yields Cannot run program "adb": error=13, Permission denied [duplicate] 【发布时间】:2019-03-11 22:49:52 【问题描述】:

我正在尝试执行以下命令:

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://***.com/a/27909315/5521089

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

注意:我尝试运行不带 adb shell 前缀的命令,但是它返回 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>

检查的设置和设备没有帐户(这是一个没有任何 google play 服务并且没有 root 的 android 设备。)。该应用的 minSdkVersion 为 21/targetSdkVersion 为 27。

最终,我希望将设备设置为所有者(没有 NFC),其唯一目的是在不征得用户许可的情况下固定屏幕。(这是一个 POS 应用程序)。如何执行命令,以便我可以将设备设置为所有者,而不会出现任何异常?

【问题讨论】:

【参考方案1】:

我正在尝试以编程方式将我的设备设置为所有者

只有两种合法方式可以将应用设置为设备所有者。

a) 设备配置

拆箱设备后,您可以使用专门准备的 NFC 标签对其进行点击。由存储在 NFC 标签上的指令指定的应用现在被设置为设备所有者。

b) 亚行

只要满足这些条件,就可以使用问题中提到的命令:

没有设置设备所有者 设备上没有注册帐户

dpm set-device-owner 命令只能从用户打开的 shell(即开发机器中的 ADB)运行。它不适用于Runtime.exec() 打开的 shell。而且,显然,即使您可以从设备 ADB 到自身,它也会受到同样的限制。

来源:

https://github.com/aosp-mirror/platform_frameworks_base/blob/2d82493ded10d88cb44e84b90a1b485d3a895d75/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java#L7172 https://github.com/aosp-mirror/platform_frameworks_base/blob/2d82493ded10d88cb44e84b90a1b485d3a895d75/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java#L12184

最终,我希望将设备设置为所有者(不带 NFC),其唯一目的是在不征得用户许可的情况下固定屏幕

您可以使用隐藏系统 API (android.app.StatusBarManager) 自己隐藏状态栏和导航按钮,并由设备制造商使用平台签名为您的应用签名 .您需要android.permission.STATUS_BAR 权限的签名。

【讨论】:

感谢发帖。 SO 帖子(我已链接)让我有点困惑,因为它们描述了能够像我一样执行确切的运行时命令。这可能是因为它们在有根设备上运行吗? 来自开发机器的 ADB 确实是我可以运行该命令的唯一方法。我进一步确定我引用的链接是针对有根设备的。【参考方案2】:

简短的回答是:您的应用无法运行 ADB 命令。如果 Android 允许这样做,那将是一个巨大的安全漏洞。

如果您想以编程方式将您的设备设置为设备管理员,请查看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);

【讨论】:

感谢发帖。是的,我已经尝试了上述方法,但是它为 devicePolicyManager.isDeviceOwnerApp() 返回 false;正如你所提到的,上面只设置了设备管理员,而不是设备所有者。删除 adb shell 前缀会更好吗?我有点困惑,因为我看到这个命令显然适用于我发布的 SO 链接。 devicePolicyManager.isDeviceOwnerApp() 什么时候返回 false?我在您的问题中的示例代码中看不到检查 启动意图是我最初的方法,但我删除了它,因为它仅适用于设备管理员。在用户为意图选择激活后,如果结果正常,我会在我的 onActvityResult() 中检查 devicePolicyManager.isDeviceOwnerApp() 并且它会返回 false。但是 devicePolicyManager.isAdminActive() 返回 true,这仍然不允许我实现在没有用户权限的情况下固定屏幕的目标。

以上是关于在应用程序中以编程方式执行 adb shell dpm 命令会产生无法运行程序“adb”:错误 = 13,权限被拒绝 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

求问 BAT脚本如何自动执行 adb shell 以后的命令

如何在android程序中执行adb shell命令

当尝试在 adb shell 中输入问号时,它显示为 d,这是为啥呢?

如何在android程序中执行adb shell命令

adb shell dumpsys 命令

如何使用 adb 在 bash 脚本中以读写方式重新安装我的 Android/系统?