Merge "Add end-to-end tests for @EnforcePermission" am: cdac5de216

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2486756

Change-Id: I838015c65392febe5044cfac37e3a5f133b7203f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Thiébaud Weksteen
2023-03-14 04:28:25 +00:00
committed by Automerger Merge Worker
11 changed files with 525 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package {
default_applicable_licenses: ["frameworks_base_license"],
}
filegroup {
name: "frameworks-enforce-permission-test-aidl",
srcs: ["aidl/**/*.aidl"],
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.tests.enforcepermission;
interface INested {
@EnforcePermission("ACCESS_NETWORK_STATE")
void ProtectedByAccessNetworkState();
@EnforcePermission("READ_SYNC_SETTINGS")
void ProtectedByReadSyncSettings();
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.tests.enforcepermission;
interface IProtected {
@EnforcePermission("INTERNET")
void ProtectedByInternet();
@EnforcePermission("VIBRATE")
void ProtectedByVibrate();
@EnforcePermission("INTERNET")
void ProtectedByInternetAndVibrateImplicitly();
@EnforcePermission("INTERNET")
void ProtectedByInternetAndAccessNetworkStateImplicitly();
@EnforcePermission("INTERNET")
void ProtectedByInternetAndReadSyncSettingsImplicitly();
}

View File

@@ -0,0 +1,23 @@
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
android_test_helper_app {
name: "EnforcePermissionTestHelper",
srcs: [
"src/**/*.java",
":frameworks-enforce-permission-test-aidl",
],
platform_apis: true,
certificate: "platform",
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.tests.enforcepermission.service">
<application>
<service
android:name=".TestService"
android:exported="true" />
<service
android:name=".NestedTestService"
android:exported="true" />
</application>
</manifest>

View File

@@ -0,0 +1,48 @@
/**
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.tests.enforcepermission.service;
import android.annotation.EnforcePermission;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.tests.enforcepermission.INested;
import android.util.Log;
public class NestedTestService extends Service {
private static final String TAG = "EnforcePermission.NestedTestService";
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return mBinder;
}
private final INested.Stub mBinder = new INested.Stub() {
@Override
@EnforcePermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void ProtectedByAccessNetworkState() {
ProtectedByAccessNetworkState_enforcePermission();
}
@Override
@EnforcePermission(android.Manifest.permission.READ_SYNC_SETTINGS)
public void ProtectedByReadSyncSettings() {
ProtectedByReadSyncSettings_enforcePermission();
}
};
}

View File

@@ -0,0 +1,119 @@
/**
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.tests.enforcepermission.service;
import android.annotation.EnforcePermission;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.tests.enforcepermission.INested;
import android.tests.enforcepermission.IProtected;
import android.util.Log;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class TestService extends Service {
private static final String TAG = "EnforcePermission.TestService";
private volatile ServiceConnection mNestedServiceConnection;
@Override
public void onCreate() {
mNestedServiceConnection = new ServiceConnection();
Intent intent = new Intent(this, NestedTestService.class);
boolean bound = bindService(intent, mNestedServiceConnection, Context.BIND_AUTO_CREATE);
if (!bound) {
Log.wtf(TAG, "bindService() on NestedTestService failed");
}
}
@Override
public void onDestroy() {
unbindService(mNestedServiceConnection);
}
private static final class ServiceConnection implements android.content.ServiceConnection {
private volatile CompletableFuture<INested> mFuture = new CompletableFuture<>();
public INested get() {
try {
return mFuture.get(1, TimeUnit.SECONDS);
} catch (ExecutionException | InterruptedException | TimeoutException e) {
throw new RuntimeException("Unable to reach NestedTestService: " + e.getMessage());
}
}
public void onServiceConnected(ComponentName className, IBinder service) {
mFuture.complete(INested.Stub.asInterface(service));
}
public void onServiceDisconnected(ComponentName className) {
mFuture = new CompletableFuture<>();
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IProtected.Stub mBinder = new IProtected.Stub() {
@Override
@EnforcePermission(android.Manifest.permission.INTERNET)
public void ProtectedByInternet() {
ProtectedByInternet_enforcePermission();
}
@Override
@EnforcePermission(android.Manifest.permission.VIBRATE)
public void ProtectedByVibrate() {
ProtectedByVibrate_enforcePermission();
}
@Override
@EnforcePermission(android.Manifest.permission.INTERNET)
public void ProtectedByInternetAndVibrateImplicitly() {
ProtectedByInternetAndVibrateImplicitly_enforcePermission();
ProtectedByVibrate();
}
@Override
@EnforcePermission(android.Manifest.permission.INTERNET)
public void ProtectedByInternetAndAccessNetworkStateImplicitly() throws RemoteException {
ProtectedByInternetAndAccessNetworkStateImplicitly_enforcePermission();
mNestedServiceConnection.get().ProtectedByAccessNetworkState();
}
@Override
@EnforcePermission(android.Manifest.permission.INTERNET)
public void ProtectedByInternetAndReadSyncSettingsImplicitly() throws RemoteException {
ProtectedByInternetAndReadSyncSettingsImplicitly_enforcePermission();
mNestedServiceConnection.get().ProtectedByReadSyncSettings();
}
};
}

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package {
default_applicable_licenses: ["frameworks_base_license"],
}
android_test {
name: "EnforcePermissionTests",
srcs: [
"src/**/*.java",
":frameworks-enforce-permission-test-aidl",
],
static_libs: [
"androidx.test.rules",
],
libs: [
"android.test.base",
"android.test.runner",
],
data: [
":EnforcePermissionTestHelper",
],
platform_apis: true,
certificate: "platform",
test_suites: ["general-tests"],
}

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.tests.enforcepermission.tests">
<!-- Expected for the tests (not actually used) -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<queries>
<package android:name="android.tests.enforcepermission.service" />
</queries>
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="android.tests.enforcepermission.tests"/>
</manifest>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration description="Runs EnforcePermission End-to-End Tests">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="EnforcePermissionTestHelper.apk"/>
<option name="test-file-name" value="EnforcePermissionTests.apk"/>
<option name="cleanup-apks" value="true" />
</target_preparer>
<option name="test-tag" value="EnforcePermissionTests"/>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="android.tests.enforcepermission.tests"/>
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
</test>
</configuration>

View File

@@ -0,0 +1,129 @@
/**
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.tests.enforcepermission.tests;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.tests.enforcepermission.IProtected;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@RunWith(AndroidJUnit4.class)
public class ServiceTest {
private static final String TAG = "EnforcePermission.Tests";
private static final String SERVICE_NAME = "android.tests.enforcepermission.service";
private static final int SERVICE_TIMEOUT_SEC = 5;
private Context mContext;
private volatile ServiceConnection mServiceConnection;
@Before
public void bindTestService() throws Exception {
Log.d(TAG, "bindTestService");
mContext = InstrumentationRegistry.getTargetContext();
mServiceConnection = new ServiceConnection();
Intent intent = new Intent();
intent.setClassName(SERVICE_NAME, SERVICE_NAME + ".TestService");
assertTrue(mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE));
}
@After
public void unbindTestService() throws Exception {
mContext.unbindService(mServiceConnection);
}
private static final class ServiceConnection implements android.content.ServiceConnection {
private volatile CompletableFuture<IProtected> mFuture = new CompletableFuture<>();
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
mFuture.complete(IProtected.Stub.asInterface(service));
}
@Override
public void onServiceDisconnected(ComponentName className) {
mFuture = new CompletableFuture<>();
}
public IProtected get() {
try {
return mFuture.get(SERVICE_TIMEOUT_SEC, TimeUnit.SECONDS);
} catch (ExecutionException | InterruptedException | TimeoutException e) {
throw new RuntimeException("Unable to reach TestService: " + e.toString());
}
}
}
@Test
public void testImmediatePermissionGranted_succeeds()
throws RemoteException {
mServiceConnection.get().ProtectedByInternet();
}
@Test
public void testImmediatePermissionNotGranted_fails()
throws RemoteException {
final Exception ex = assertThrows(SecurityException.class,
() -> mServiceConnection.get().ProtectedByVibrate());
assertThat(ex.getMessage(), containsString("VIBRATE"));
}
@Test
public void testImmediatePermissionGrantedButImplicitLocalNotGranted_fails()
throws RemoteException {
final Exception ex = assertThrows(SecurityException.class,
() -> mServiceConnection.get().ProtectedByInternetAndVibrateImplicitly());
assertThat(ex.getMessage(), containsString("VIBRATE"));
}
@Test
public void testImmediatePermissionGrantedButImplicitNestedNotGranted_fails()
throws RemoteException {
final Exception ex = assertThrows(SecurityException.class,
() -> mServiceConnection.get()
.ProtectedByInternetAndAccessNetworkStateImplicitly());
assertThat(ex.getMessage(), containsString("ACCESS_NETWORK_STATE"));
}
@Test
public void testImmediatePermissionGrantedAndImplicitNestedGranted_succeeds()
throws RemoteException {
mServiceConnection.get().ProtectedByInternetAndReadSyncSettingsImplicitly();
}
}