Run Package Manager install on Android 12 with runtime.exec

I have a Samsung tablet with root access running Android 12. I am trying to install apks on this device using the Package Manager with the following code:

String command = "pm install -r -g -t "+ mApkDirectory + apkName +" \n";
process = Runtime.getRuntime().exec("su");

DataOutputStream os = new DataOutputStream(process.getOutputStream());  
os.writeBytes(command);  
os.writeBytes("exit\n"); 
os.flush();

InputStream stdin = process.getInputStream();
InputStreamReader isr = new InputStreamReader(stdin);
BufferedReader br = new BufferedReader(isr);
String line = null;

// install output
StringBuffer strBuffer = new StringBuffer();
while((line = br.readLine()) != null){
   strBuffer.append(line);
}
                        
int exitCode = process.waitFor();

This code works on Android versions 7.x and lower, but on Android 12 I get an exit code of 255. What am I missing?

The exit code of 255 typically indicates a permission issue. Starting from Android 8.0, the pm install command requires the INSTALL_PACKAGES permission, which is only granted to system apps/privilege apps by default.

To fix this issue, you need to grant the INSTALL_PACKAGES permission to your app. However, keep in mind that gaining this permission requires your app to be signed with the platform key or installed in the system partition.

If your app meets these requirements, you can add the android.permission.INSTALL_PACKAGES permission to your AndroidManifest.xml file:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">

    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />

    <!-- Other permissions and components -->

</manifest>

Additionally, you need to request the runtime permission from the user if your app targets Android 6.0 (API level 23) or higher. You can use the following code to request the permission:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) {
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
            Uri.parse("package:" + context.getPackageName()));
    startActivityForResult(intent, REQUEST_CODE);
}

Make sure to handle the permission result in onActivityResult().

Once you have the necessary permissions, the pm install command should work as expected on Android 12.