Permission Teseter update sdk37#57
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the Permission Test Tooling and Companion app to support Android 17 / SDK 37 (CinnamonBun). Key changes include upgrading compileSdk and targetSdk to 37, adding several new services and permissions (such as CAPTURE_KEYBOARD, ACCESS_LOCAL_NETWORK, and various BIND_* permissions), implementing CinnamonBun-specific test suites, and introducing instrumentation tests like CaptureKeyboardTest and InjectKeyEventsTest. Feedback from the reviewer highlights several critical issues: a potential NoSuchMethodError on devices below API 33 due to the direct use of stopForeground(int) when minSdk is 28; a major regression in SignatureTestSuite where legacy signature test modules were accidentally removed; thread-safety concerns with receivedKeyCodes in MainActivity being accessed across threads; and multiple potential NullPointerException crashes in exception handling and system service lookups (e.g., CompanionDeviceManager and DevicePolicyManager).
| } | ||
| } | ||
| stopForeground(Service.STOP_FOREGROUND_DETACH); | ||
| stopForeground(Service.STOP_FOREGROUND_REMOVE); |
There was a problem hiding this comment.
Calling stopForeground(int) directly will throw a NoSuchMethodError at runtime on devices running API levels lower than 33 (Android 13), because the project's minSdk is set to 28 and this method overload was introduced in API 33. To support older versions, check the SDK version before calling the newer API, or fallback to the deprecated stopForeground(boolean) method.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
stopForeground(Service.STOP_FOREGROUND_REMOVE);
} else {
stopForeground(true);
}| SignatureTestModuleV(activity), | ||
| SignatureTestModuleBaklava(activity), | ||
| SignatureTestModuleBinder(activity) | ||
| SignatureTestModuleCinnamonBun(activity) |
There was a problem hiding this comment.
Removing all other signature test modules (P, Q, R, S, T, U, V, Baklava, Binder, etc.) from SignatureTestSuite is a major regression that disables testing for all legacy signature permissions. Please restore the legacy modules to ensure comprehensive test coverage.
SignatureTestModule(activity),
SignatureTestModuleP(activity),
SignatureTestModuleQ(activity),
SignatureTestModuleR(activity),
SignatureTestModuleS(activity),
SignatureTestModuleT(activity),
SignatureTestModuleU(activity),
SignatureTestModuleV(activity),
SignatureTestModuleBaklava(activity),
SignatureTestModuleBinder(activity),
SignatureTestModuleCinnamonBun(activity)| //Change the test modules here by resource settings | ||
| lateinit var suites:MutableList<PermissionTestSuiteBase> | ||
| lateinit var mCurrentModule: PermissionTestModuleBase | ||
| val receivedKeyCodes = mutableListOf<Int>() |
There was a problem hiding this comment.
The receivedKeyCodes list is accessed from both the main UI thread (via onKeyDown) and the instrumentation test thread (via CaptureKeyboardTest and InjectKeyEventsTest). Since mutableListOf() creates a non-thread-safe ArrayList, this can lead to race conditions or ConcurrentModificationException. Using a thread-safe CopyOnWriteArrayList resolves this issue.
val receivedKeyCodes = java.util.concurrent.CopyOnWriteArrayList<Int>()| } catch (java.lang.reflect.InvocationTargetException e) { | ||
| if (e.getCause() instanceof SecurityException) { | ||
| throw (SecurityException) e.getCause(); | ||
| } else if (e.getCause() instanceof IllegalStateException && e.getCause().getMessage().contains("flag disabled")) { |
There was a problem hiding this comment.
If e.getCause().getMessage() returns null, calling .contains("flag disabled") will throw a NullPointerException. Adding a null check prevents this potential crash.
| } else if (e.getCause() instanceof IllegalStateException && e.getCause().getMessage().contains("flag disabled")) { | |
| } else if (e.getCause() instanceof IllegalStateException && e.getCause().getMessage() != null && e.getCause().getMessage().contains("flag disabled")) { |
| socket.connect(new java.net.InetSocketAddress("127.0.0.1", 65535), 100); | ||
| socket.close(); | ||
| } catch (java.net.SocketException e) { | ||
| if (e.getMessage().contains("EACCES") || e.getMessage().contains("EPERM")) { |
There was a problem hiding this comment.
If e.getMessage() is null, calling .contains("EACCES") or .contains("EPERM") will throw a NullPointerException. Adding a null check prevents this potential crash.
| if (e.getMessage().contains("EACCES") || e.getMessage().contains("EPERM")) { | |
| if (e.getMessage() != null && (e.getMessage().contains("EACCES") || e.getMessage().contains("EPERM"))) { |
|
|
||
| @PermissionTest(permission="REQUEST_COMPANION_PROFILE_VIRTUAL_DEVICE", sdkMin=37) | ||
| public void testRequestCompanionProfileVirtualDevice(){ | ||
| android.companion.CompanionDeviceManager companionDeviceManager = mContext.getSystemService(android.companion.CompanionDeviceManager.class); |
There was a problem hiding this comment.
If CompanionDeviceManager is not supported on the device (e.g., on some customized builds or low-end devices), mContext.getSystemService will return null. Calling associate on a null reference will throw a NullPointerException. Adding a null check prevents this crash.
android.companion.CompanionDeviceManager companionDeviceManager = mContext.getSystemService(android.companion.CompanionDeviceManager.class);
if (companionDeviceManager == null) {
logger.debug("CompanionDeviceManager is null");
return;
}| android.app.admin.DevicePolicyManager dpm = (android.app.admin.DevicePolicyManager) mContext.getSystemService(android.content.Context.DEVICE_POLICY_SERVICE); | ||
| java.lang.reflect.Method method = dpm.getClass().getMethod("getMultiuserManagedDeviceProvisioningState"); |
There was a problem hiding this comment.
If DevicePolicyManager is not supported on the device, mContext.getSystemService will return null. Calling getClass() on a null reference will throw a NullPointerException. Adding a null check prevents this crash.
android.app.admin.DevicePolicyManager dpm = (android.app.admin.DevicePolicyManager) mContext.getSystemService(android.content.Context.DEVICE_POLICY_SERVICE);
if (dpm == null) {
logger.debug("DevicePolicyManager is null");
return;
}
java.lang.reflect.Method method = dpm.getClass().getMethod("getMultiuserManagedDeviceProvisioningState");
Here's Permission Tester updates for sdk 37