From c15078b90091ecda7e5b7920aa9a8fbe58317bf7 Mon Sep 17 00:00:00 2001 From: Omar El Sheikh Date: Mon, 6 Jul 2020 15:54:43 -0400 Subject: [PATCH] Added Scoped Storage Support for Android Updated permissions for the renderdoccmd app based on which version of android the app is running on **WRITE_EXTERNAL_STORAGE for =R Updated the Java portion of renderdoccmd to check/request the correct permission based on android version Changed the file path for renderdoc files on Android based on the version of Android the connected device is running **/sdcard/Android/data/$PACKAGE_NAME for =R --- renderdoc/android/android.cpp | 10 +++-- renderdoc/android/android_utils.cpp | 13 ++++++ renderdoc/android/android_utils.h | 1 + .../os/posix/android/android_stringio.cpp | 11 ++++- renderdoccmd/android/AndroidManifest.xml | 3 +- renderdoccmd/android/Loader.java | 41 ++++++++++++++----- 6 files changed, 63 insertions(+), 16 deletions(-) diff --git a/renderdoc/android/android.cpp b/renderdoc/android/android.cpp index 9bc2f4f57..aa51af0a6 100644 --- a/renderdoc/android/android.cpp +++ b/renderdoc/android/android.cpp @@ -1218,6 +1218,8 @@ ExecuteResult AndroidRemoteServer::ExecuteAndInject(const char *a, const char *w "shell setprop debug.vulkan.layers " RENDERDOC_VULKAN_LAYER_NAME); } + rdcstr folderName = Android::GetFolderName(m_deviceID); + // if in VR mode, enable frame delimiter markers Android::adbExecCommand(m_deviceID, "shell setprop debug.vr.profiler 1"); @@ -1228,9 +1230,9 @@ ExecuteResult AndroidRemoteServer::ExecuteAndInject(const char *a, const char *w // Android/data/ // has the permissions set correctly, and we don't have a convenient way to get the package name // from native code. - Android::adbExecCommand(m_deviceID, "shell mkdir -p /sdcard/Android/data/" + processName); - Android::adbExecCommand(m_deviceID, - "shell mkdir -p /sdcard/Android/data/" + processName + "/files"); + Android::adbExecCommand(m_deviceID, "shell mkdir -p /sdcard/Android/" + folderName + processName); + Android::adbExecCommand( + m_deviceID, "shell mkdir -p /sdcard/Android/" + folderName + processName + "/files"); // set our property with the capture options encoded, to be picked up by the library on the // device Android::adbExecCommand(m_deviceID, @@ -1239,7 +1241,7 @@ ExecuteResult AndroidRemoteServer::ExecuteAndInject(const char *a, const char *w // try to push our settings file into the appdata folder Android::adbExecCommand(m_deviceID, "push \"" + FileIO::GetAppFolderFilename("renderdoc.conf") + - "\" /sdcard/Android/data/" + processName + + "\" /sdcard/Android/" + folderName + processName + "/files/renderdoc.conf"); rdcstr installedPath = Android::GetPathForPackage(m_deviceID, packageName); diff --git a/renderdoc/android/android_utils.cpp b/renderdoc/android/android_utils.cpp index f880d0ff3..d5bab3edb 100644 --- a/renderdoc/android/android_utils.cpp +++ b/renderdoc/android/android_utils.cpp @@ -188,6 +188,19 @@ bool IsSupported(rdcstr deviceID) return true; } +rdcstr GetFolderName(const rdcstr &deviceID) +{ + rdcstr api = + Android::adbExecCommand(deviceID, "shell getprop ro.build.version.sdk").strStdout.trimmed(); + + int apiVersion = atoi(api.c_str()); + + if(apiVersion >= 30) + return "media/"; + + return "data/"; +} + bool SupportsNativeLayers(const rdcstr &deviceID) { rdcstr api = diff --git a/renderdoc/android/android_utils.h b/renderdoc/android/android_utils.h index a297df346..5627fd21c 100644 --- a/renderdoc/android/android_utils.h +++ b/renderdoc/android/android_utils.h @@ -70,6 +70,7 @@ rdcstr GetPlainABIName(ABI abi); rdcarray GetSupportedABIs(const rdcstr &deviceID); rdcstr GetRenderDocPackageForABI(ABI abi); rdcstr GetPathForPackage(const rdcstr &deviceID, const rdcstr &packageName); +rdcstr GetFolderName(const rdcstr &deviceID); bool PatchManifest(bytebuf &manifest); }; diff --git a/renderdoc/os/posix/android/android_stringio.cpp b/renderdoc/os/posix/android/android_stringio.cpp index 4f8e18b28..253f13c48 100644 --- a/renderdoc/os/posix/android/android_stringio.cpp +++ b/renderdoc/os/posix/android/android_stringio.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "common/common.h" #include "common/formatting.h" @@ -68,7 +69,15 @@ rdcstr GetTempRootPath() // This is the same as returned by getExternalFilesDir(). It might possibly change in the future. rdcstr package; GetExecutableFilename(package); - return "/sdcard/Android/data/" + package + "/files"; + + char platformVersionChar[PROP_VALUE_MAX]; + __system_property_get("ro.build.version.sdk", platformVersionChar); + int platformVersion = atoi(platformVersionChar); + + if(platformVersion < 30) + return "/sdcard/Android/data/" + package + "/files"; + else + return "/sdcard/Android/media/" + package + "/files"; } rdcstr GetAppFolderFilename(const rdcstr &filename) diff --git a/renderdoccmd/android/AndroidManifest.xml b/renderdoccmd/android/AndroidManifest.xml index f9ac6af99..b13155088 100644 --- a/renderdoccmd/android/AndroidManifest.xml +++ b/renderdoccmd/android/AndroidManifest.xml @@ -4,7 +4,8 @@ - + + diff --git a/renderdoccmd/android/Loader.java b/renderdoccmd/android/Loader.java index 557db70a9..a97ec49df 100644 --- a/renderdoccmd/android/Loader.java +++ b/renderdoccmd/android/Loader.java @@ -2,6 +2,8 @@ package @RENDERDOC_ANDROID_PACKAGE_NAME@; import android.os.Build; import android.app.Activity; import android.view.WindowManager; +import android.os.Environment; +import android.content.Intent; public class Loader extends android.app.NativeActivity { @@ -20,18 +22,37 @@ public class Loader extends android.app.NativeActivity if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return; - // Popup a dialog if we haven't granted Android storage permissions. - requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); + String[] permission = new String[1]; + if (Build.VERSION.SDK_INT < 30 /*Build.VERSION_CODES.R*/) { + permission[0] = android.Manifest.permission.WRITE_EXTERNAL_STORAGE; - // Request is asynchronous, so prevent connection to server until permissions granted. - while(checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) - != android.content.pm.PackageManager.PERMISSION_GRANTED) - { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - break; + requestPermissions(permission, 1); + + // Request is asynchronous, so prevent connection to server until permissions granted. + while(checkSelfPermission(permission[0]) + != android.content.pm.PackageManager.PERMISSION_GRANTED) + { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + break; + } } } + else { + permission[0] = "android.permission.MANAGE_EXTERNAL_STORAGE"; // android.Manifest.permission.MANAGE_EXTERNAL_STORAGE; + + try { + java.lang.reflect.Method method = Environment.class.getMethod("isExternalStorageManager"); + + Boolean result = (Boolean)method.invoke(null); + + // Popup a dialog if we haven't granted Android storage permissions. + if (!result) { + Intent viewIntent = new Intent( "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION" /*android.provider.Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION*/); + startActivity(viewIntent); + } + } catch(Exception e) { } + } } }