diff --git a/android/build.gradle b/android/build.gradle index 723be882982..d0ae3b9c886 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -14,7 +14,7 @@ android { } compileSdkVersion 34 defaultConfig { - minSdkVersion 21 + minSdkVersion 22 targetSdkVersion 33 versionCode 1 versionName "1.0" diff --git a/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java b/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java index e56ce5fc405..54b38bc3bd3 100644 --- a/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java +++ b/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java @@ -217,7 +217,6 @@ private void configureNetworkMonitoring() { connectivityManager.registerDefaultNetworkCallback(defaultNetworkCallback); unregisterRunnable = new Runnable() { - @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public void run() { connectivityManager.unregisterNetworkCallback(defaultNetworkCallback); @@ -231,7 +230,6 @@ public void run() { context.registerReceiver(networkReceiver, networkIntentFilter); unregisterRunnable = new Runnable() { - @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public void run() { context.unregisterReceiver(networkReceiver); diff --git a/binder/build.gradle b/binder/build.gradle index dc9df6b04de..d1302ddfed0 100644 --- a/binder/build.gradle +++ b/binder/build.gradle @@ -13,7 +13,7 @@ android { targetCompatibility 1.8 } defaultConfig { - minSdkVersion 21 + minSdkVersion 22 targetSdkVersion 33 versionCode 1 versionName "1.0" diff --git a/binder/src/main/java/io/grpc/binder/SecurityPolicies.java b/binder/src/main/java/io/grpc/binder/SecurityPolicies.java index 05e8c43da79..c0f6fe81989 100644 --- a/binder/src/main/java/io/grpc/binder/SecurityPolicies.java +++ b/binder/src/main/java/io/grpc/binder/SecurityPolicies.java @@ -184,7 +184,6 @@ public Status checkAuthorization(int uid) { * Creates {@link SecurityPolicy} which checks if the app is a device owner app. See {@link * DevicePolicyManager}. */ - @RequiresApi(18) public static io.grpc.binder.SecurityPolicy isDeviceOwner(Context applicationContext) { DevicePolicyManager devicePolicyManager = (DevicePolicyManager) applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE); @@ -199,7 +198,6 @@ public static io.grpc.binder.SecurityPolicy isDeviceOwner(Context applicationCon * Creates {@link SecurityPolicy} which checks if the app is a profile owner app. See {@link * DevicePolicyManager}. */ - @RequiresApi(21) public static SecurityPolicy isProfileOwner(Context applicationContext) { DevicePolicyManager devicePolicyManager = (DevicePolicyManager) applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE); diff --git a/binder/src/main/java/io/grpc/binder/internal/ServiceBinding.java b/binder/src/main/java/io/grpc/binder/internal/ServiceBinding.java index f0cbe9ec56b..42d69d27a2e 100644 --- a/binder/src/main/java/io/grpc/binder/internal/ServiceBinding.java +++ b/binder/src/main/java/io/grpc/binder/internal/ServiceBinding.java @@ -193,18 +193,27 @@ private static Status bindInternal( bindResult = context.bindService(bindIntent, conn, flags); break; case BIND_SERVICE_AS_USER: - bindResult = context.bindServiceAsUser(bindIntent, conn, flags, targetUserHandle); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + bindResult = context.bindServiceAsUser(bindIntent, conn, flags, targetUserHandle); + } else { + return Status.INTERNAL.withDescription("Cross user Channel requires Android R+"); + } break; case DEVICE_POLICY_BIND_SEVICE_ADMIN: DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); - bindResult = - devicePolicyManager.bindDeviceAdminServiceAsUser( - channelCredentials.getDevicePolicyAdminComponentName(), - bindIntent, - conn, - flags, - targetUserHandle); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + bindResult = + devicePolicyManager.bindDeviceAdminServiceAsUser( + channelCredentials.getDevicePolicyAdminComponentName(), + bindIntent, + conn, + flags, + targetUserHandle); + } else { + return Status.INTERNAL.withDescription( + "Device policy admin binding requires Android R+"); + } break; } if (!bindResult) { diff --git a/binder/src/test/java/io/grpc/binder/internal/ServiceBindingTest.java b/binder/src/test/java/io/grpc/binder/internal/ServiceBindingTest.java index bd51c522d15..2079b0eed2c 100644 --- a/binder/src/test/java/io/grpc/binder/internal/ServiceBindingTest.java +++ b/binder/src/test/java/io/grpc/binder/internal/ServiceBindingTest.java @@ -29,6 +29,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ServiceInfo; +import android.os.Build; import android.os.IBinder; import android.os.Parcel; import android.os.UserHandle; @@ -327,6 +328,50 @@ public void testResolveNonExistentServiceWithTargetUserThrows() throws Exception assertThat(statusException.getStatus().getDescription()).contains("12345"); } + @Test + @Config(sdk = 30) + public void testBindService_doesNotThrowInternalErrorWhenSdkAtLeastR() { + UserHandle userHandle = generateUserHandle(/* userId= */ 12345); + binding = newBuilder().setTargetUserHandle(userHandle).build(); + binding.bind(); + shadowOf(getMainLooper()).idle(); + + assertThat(Build.VERSION.SDK_INT).isEqualTo(Build.VERSION_CODES.R); + assertThat(observer.unboundReason).isNull(); + } + + @Test + @Config(sdk = 28) + public void testBindServiceAsUser_returnsErrorWhenSdkBelowR() { + UserHandle userHandle = generateUserHandle(/* userId= */ 12345); + binding = newBuilder().setTargetUserHandle(userHandle).build(); + binding.bind(); + shadowOf(getMainLooper()).idle(); + + assertThat(observer.unboundReason.getCode()).isEqualTo(Code.INTERNAL); + assertThat(observer.unboundReason.getDescription()) + .isEqualTo("Cross user Channel requires Android R+"); + } + + @Test + @Config(sdk = 28) + public void testDevicePolicyBlind_returnsErrorWhenSdkBelowR() { + String deviceAdminClassName = "DevicePolicyAdmin"; + ComponentName adminComponent = new ComponentName(appContext, deviceAdminClassName); + allowBindDeviceAdminForUser(appContext, adminComponent, 10); + binding = + newBuilder() + .setTargetUserHandle(UserHandle.getUserHandleForUid(10)) + .setChannelCredentials(BinderChannelCredentials.forDevicePolicyAdmin(adminComponent)) + .build(); + binding.bind(); + shadowOf(getMainLooper()).idle(); + + assertThat(observer.unboundReason.getCode()).isEqualTo(Code.INTERNAL); + assertThat(observer.unboundReason.getDescription()) + .isEqualTo("Device policy admin binding requires Android R+"); + } + @Test @Config(sdk = 30) public void testBindWithDeviceAdmin() throws Exception { diff --git a/cronet/build.gradle b/cronet/build.gradle index 3cc86201298..0715b4129bf 100644 --- a/cronet/build.gradle +++ b/cronet/build.gradle @@ -14,7 +14,7 @@ android { namespace = 'io.grpc.cronet' compileSdkVersion 33 defaultConfig { - minSdkVersion 21 + minSdkVersion 22 targetSdkVersion 33 versionCode 1 versionName "1.0" diff --git a/lint.xml b/lint.xml new file mode 100644 index 00000000000..93e2f603108 --- /dev/null +++ b/lint.xml @@ -0,0 +1,8 @@ + + + + +