diff options
author | 2022-01-25 19:29:17 +0000 | |
---|---|---|
committer | 2022-01-25 19:29:17 +0000 | |
commit | b649e4184331ca38d55c5da8d2d8f2b71f56b102 (patch) | |
tree | 1b16fb90bff2ace26ddfc8d9bfe2a4b314913683 | |
parent | 0b6c9488af0db2161cb03718dad1f02f275bbaf1 (diff) | |
parent | 234642a055ea4f341fa8a8f92c1a8a3f00f6a77a (diff) |
Merge "Readd basic Safety Center resources"
18 files changed, 794 insertions, 1 deletions
diff --git a/SafetyCenter/Resources/Android.bp b/SafetyCenter/Resources/Android.bp new file mode 100644 index 000000000..e82392646 --- /dev/null +++ b/SafetyCenter/Resources/Android.bp @@ -0,0 +1,34 @@ +// +// Copyright (C) 2021 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. +// + +// APK to hold all the Safety Center overlayable resources. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_app { + name: "SafetyCenterResources", + privileged: true, + sdk_version: "system_current", + min_sdk_version: "30", + apex_available: ["com.android.permission"], + certificate: ":com.android.safetycenter.resources.certificate", +} + +android_app_certificate { + name: "com.android.safetycenter.resources.certificate", + certificate: "com.android.safetycenter.resources" +} diff --git a/SafetyCenter/Resources/AndroidManifest.xml b/SafetyCenter/Resources/AndroidManifest.xml new file mode 100644 index 000000000..9804f476b --- /dev/null +++ b/SafetyCenter/Resources/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 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 for Safety Center resources APK --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.safetycenter.resources" + coreApp="true" + android:versionCode="319999900" + android:versionName="31 system image"> + <application + android:label="@string/safetyCenterResourcesAppLabel" + android:defaultToDeviceProtectedStorage="true" + android:directBootAware="true"> + <!-- This is only used to identify this app by resolving the action. + The activity is never actually triggered. --> + <activity + android:name="android.app.Activity" + android:exported="true"> + <intent-filter> + <action android:name="com.android.safetycenter.intent.action.SAFETY_CENTER_RESOURCES_APK" /> + </intent-filter> + </activity> + </application> +</manifest>
\ No newline at end of file diff --git a/SafetyCenter/Resources/com.android.safetycenter.resources.pem b/SafetyCenter/Resources/com.android.safetycenter.resources.pem new file mode 100644 index 000000000..3c9f83c29 --- /dev/null +++ b/SafetyCenter/Resources/com.android.safetycenter.resources.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +YnA8BkENvW/4fVCfFP+nH0+jq8IxtQ== +-----END PRIVATE KEY----- diff --git a/SafetyCenter/Resources/com.android.safetycenter.resources.pk8 b/SafetyCenter/Resources/com.android.safetycenter.resources.pk8 Binary files differnew file mode 100644 index 000000000..74fbd4523 --- /dev/null +++ b/SafetyCenter/Resources/com.android.safetycenter.resources.pk8 diff --git a/SafetyCenter/Resources/com.android.safetycenter.resources.x509.pem b/SafetyCenter/Resources/com.android.safetycenter.resources.x509.pem new file mode 100644 index 000000000..e22d1aad3 --- /dev/null +++ b/SafetyCenter/Resources/com.android.safetycenter.resources.x509.pem @@ -0,0 +1,36 @@ +-----BEGIN CERTIFICATE----- +MIIGQzCCBCugAwIBAgIUfp6Dp8jfBYD+u1qYkcMvYQKrNHYwDQYJKoZIhvcNAQEL +BQAwga8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH +DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy +b2lkMSswKQYDVQQDDCJjb20uYW5kcm9pZC5zYWZldHljZW50ZXIucmVzb3VyY2Vz +MSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMCAXDTIxMTIwNjE0 +Mjc0NVoYDzQ3NTkxMTAyMTQyNzQ1WjCBrzELMAkGA1UEBhMCVVMxEzARBgNVBAgM +CkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0Fu +ZHJvaWQxEDAOBgNVBAsMB0FuZHJvaWQxKzApBgNVBAMMImNvbS5hbmRyb2lkLnNh +ZmV0eWNlbnRlci5yZXNvdXJjZXMxIjAgBgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5k +cm9pZC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDP+8izeSt/ +AIWnVKIddgKU8gGOkZjlHN1B9E0uMolL15/qMDlkehwKrTVNjIZddV1R4lcDLJa6 +IMa/GsFlXeg5hn25O95vG9D5c2ypMYhxBXggXl4eII8eMPfvk7G3ryD01vdx+jAm +tdNwJrdOKWOMncbj3Y7fPK7uA/FloF1sTkuw9Y7VLf/mX/11b7iwSma2LsqRbzcs +gFItUXFjlF1myK9TA8dT01BrcwnJ5AXY+P8fr18encBJhBZm7unoS0sNVuHgwqu/ +n943bYoDZP9Jc33gL26qcyN/LRmY6HMOq0ZzRR0GfunaDemcBD/Z0k+dIpeKPWWf +p3f0r2P1ZJKdQSPumU1LInHbGVoBRBaI94gtHyv0RTYtrBoqHcFGF5thgV9LTZFw +W0r6sVlguzPTInmRs1m04df7OEmNBqeIeNb+5U35YpJMzxe124OK1Ex5rlYF25fd +80fKqH8zBxSncAtju8WhVtLZrFc/WOvctcuJ91UJy7OkDz72Uy00jPm/0f7y7P4h +nSoXfUgOjvniLwINhXF32dnI4WqyFJKoTP0Btn1ofmDjcUtfIwb4iTwKBlRb1PpA +kwJQweqZ1pbab759KNfEg92Bdr2xqH6Iz0SQHLL2osa+Mofm9whhBjsErFtlxOZx +GA3zgmuOnmCzzIpIa2BjuIOJA7QPi7EjlQIDAQABo1MwUTAdBgNVHQ4EFgQUVaQt +WT53h5UIovqc/xyd94KOV5gwHwYDVR0jBBgwFoAUVaQtWT53h5UIovqc/xyd94KO +V5gwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAw76A4zktQj4o +PWCBRucrfauiYe4ENpybN0U13MCEOFKx9qRL0sXwV/ZN7QAvs62y8Lw3ytAlihwp +4CM45/DBCwIwLkTS5sw9axzNKHoFdGLsMHH3p96skYNfTBKshL602ZOHHyt3CrpO +ZLOPyvt0/TKajZ1K5O1lB4S60qcJkq9P6xg80qV66NbNjT84yKq8Y1lDJbJEnRB2 +BXjr02RhuAOe7jB8VKcBeKWsKBP95DBX+QV9wqSoS9Pnet3Etb66ddfWQ5m/bkoh +lRcjpruYnEUk/7jYhJRzpmivyAnMVSas/oQZnSFUgFVl71RO05gyrWMSQt4kCAKB +ZwEcVI+2z8rzTtMM0PtRgp6TCQ7QwoQQiGjakq2aFOR0gsUpjaFroP2q73uB2c2Y +vS9VY78tPCI3RXkspA5sRJRafZ7KIBqqpUvKSd7woGDL7fQxtaq8XSUOyPP3CfZa +fhjQ1PAKYnjlUGmcWAKHaXo2uWsh2sNa9ycS2p05AwC8lNqs1p1Fde07Zw4PclVY +QN+N31b+2Byw9vI5bnIE9NflgHry3bMeFxctq3VyrAnJffL2JtaodRwDbqDCHbcb +pg573cqjzPppqw++zJWZFWNP06sTtF/Y7pDrrumJNgW0dtZWEN/pj0mtZdDSi+pa +aHU1vVK/5HwBfqkyYfklVk1NHvAx6y8= +-----END CERTIFICATE----- diff --git a/SafetyCenter/Resources/res/raw/safety_center_config.xml b/SafetyCenter/Resources/res/raw/safety_center_config.xml new file mode 100644 index 000000000..d3c0125cf --- /dev/null +++ b/SafetyCenter/Resources/res/raw/safety_center_config.xml @@ -0,0 +1,29 @@ +<!-- + ~ Copyright (C) 2021 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. + --> + +<safety-center-config> + <safety-sources-config> + <!-- TODO(b/214567659): Finalize base XML config --> + <safety-sources-group + id="TODO" + title="@string/reference" + summary="@string/reference"> + <safety-source + type="3" + id="TODO"/> + </safety-sources-group> + </safety-sources-config> +</safety-center-config> diff --git a/SafetyCenter/Resources/res/values/strings.xml b/SafetyCenter/Resources/res/values/strings.xml new file mode 100644 index 000000000..594d20d7b --- /dev/null +++ b/SafetyCenter/Resources/res/values/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 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. + --> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- The Safety Center resources package is an internal system package that provides + configuration values for the Safety Center. This is the name of the package to display in + the list of system apps. [CHAR LIMIT=40] --> + <string name="safetyCenterResourcesAppLabel">Safety Center Resources</string> + + <!-- Temporary reference --> + <string name="reference" translatable="false">Reference</string> +</resources> diff --git a/SafetyCenter/ResourcesLib/Android.bp b/SafetyCenter/ResourcesLib/Android.bp new file mode 100644 index 000000000..274386b22 --- /dev/null +++ b/SafetyCenter/ResourcesLib/Android.bp @@ -0,0 +1,37 @@ +// +// Copyright (C) 2021 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. +// + +// Library to manage all the Safety Center overlayable resources. +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +java_library { + name: "safety-center-resources-lib", + srcs: [ + "java/**/*.java", + ], + libs: [ + "framework-annotations-lib", + ], + apex_available: [ + "com.android.permission", + "test_com.android.permission", + ], + installable: false, + min_sdk_version: "30", + sdk_version: "module_current", +} diff --git a/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java b/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java new file mode 100644 index 000000000..672c57b45 --- /dev/null +++ b/SafetyCenter/ResourcesLib/java/com/android/safetycenter/resources/SafetyCenterResourcesContext.java @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2022 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 com.android.safetycenter.resources; + +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.util.Log; + +import java.io.File; +import java.io.InputStream; +import java.util.List; + +/** + * Wrapper for context to override getResources method. Resources for the Safety Center that need to + * be fetched from the dedicated resources APK. + */ +public class SafetyCenterResourcesContext extends ContextWrapper { + private static final String TAG = "SafetyCenterResContext"; + + /** Intent action that is used to identify the Safety Center resources APK */ + private static final String RESOURCES_APK_ACTION = + "com.android.safetycenter.intent.action.SAFETY_CENTER_RESOURCES_APK"; + + /** Permission APEX name */ + private static final String APEX_MODULE_NAME = "com.android.permission"; + + /** + * The path where the Permission apex is mounted. + * Current value = "/apex/com.android.permission" + */ + private static final String APEX_MODULE_PATH = + new File("/apex", APEX_MODULE_NAME).getAbsolutePath(); + + /** Raw XML config resource name */ + private static final String CONFIG_NAME = "safety_center_config"; + + /** Intent action that is used to identify the Safety Center resources APK */ + @NonNull + private final String mResourcesApkAction; + + /** The path where the Safety Center resources APK is expected to be installed */ + @Nullable + private final String mResourcesApkPath; + + /** Raw XML config resource name */ + @NonNull + private final String mConfigName; + + /** Specific flags used for retrieving resolve info */ + private final int mFlags; + + // Cached package name and resources from the resources APK + @Nullable + private String mResourcesApkPkgName; + @Nullable + private AssetManager mAssetsFromApk; + @Nullable + private Resources mResourcesFromApk; + @Nullable + private Resources.Theme mThemeFromApk; + + public SafetyCenterResourcesContext(@NonNull Context contextBase) { + super(contextBase); + mResourcesApkAction = RESOURCES_APK_ACTION; + mResourcesApkPath = APEX_MODULE_PATH; + mConfigName = CONFIG_NAME; + mFlags = PackageManager.MATCH_SYSTEM_ONLY; + } + + SafetyCenterResourcesContext(@NonNull Context contextBase, @NonNull String resourcesApkAction, + @Nullable String resourcesApkPath, @NonNull String configName, int flags) { + super(contextBase); + mResourcesApkAction = requireNonNull(resourcesApkAction); + mResourcesApkPath = resourcesApkPath; + mConfigName = requireNonNull(configName); + mFlags = flags; + } + + /** Get the package name of the Safety Center resources APK. */ + @Nullable + public String getResourcesApkPkgName() { + if (mResourcesApkPkgName != null) { + return mResourcesApkPkgName; + } + + List<ResolveInfo> resolveInfos = getPackageManager().queryIntentActivities( + new Intent(mResourcesApkAction), mFlags); + + if (resolveInfos.size() > 1) { + // multiple apps found, log a warning, but continue + Log.w(TAG, "Found > 1 APK that can resolve Safety Center resources APK intent:"); + final int resolveInfosSize = resolveInfos.size(); + for (int i = 0; i < resolveInfosSize; i++) { + ResolveInfo resolveInfo = resolveInfos.get(i); + Log.w(TAG, String.format("- pkg:%s at:%s", + resolveInfo.activityInfo.applicationInfo.packageName, + resolveInfo.activityInfo.applicationInfo.sourceDir)); + } + } + + ResolveInfo info = null; + // Assume the first good ResolveInfo is the one we're looking for + final int resolveInfosSize = resolveInfos.size(); + for (int i = 0; i < resolveInfosSize; i++) { + ResolveInfo resolveInfo = resolveInfos.get(i); + if (mResourcesApkPath != null + && !resolveInfo.activityInfo.applicationInfo.sourceDir.startsWith( + mResourcesApkPath)) { + // skip apps that don't live in the Permission apex + continue; + } + info = resolveInfo; + break; + } + + if (info == null) { + // Resource APK not loaded yet, print a stack trace to see where this is called from + Log.e(TAG, + "Attempted to fetch resources before Safety Center resources APK is loaded!", + new IllegalStateException()); + return null; + } + + mResourcesApkPkgName = info.activityInfo.applicationInfo.packageName; + Log.i(TAG, "Found Safety Center resources APK at: " + mResourcesApkPkgName); + return mResourcesApkPkgName; + } + + /** Get the Safety Center config in the Safety Center resources APK. */ + @Nullable + public InputStream getSafetyCenterConfig() { + String resoursePkgName = getResourcesApkPkgName(); + if (resoursePkgName == null) { + return null; + } + Resources resources = getResources(); + if (resources == null) { + return null; + } + int id = resources.getIdentifier(mConfigName, "raw", resoursePkgName); + if (id == 0) { + return null; + } + return resources.openRawResource(id); + } + + @Nullable + private Context getResourcesApkContext() { + String name = getResourcesApkPkgName(); + if (name == null) { + return null; + } + try { + return createPackageContext(name, 0); + } catch (PackageManager.NameNotFoundException e) { + Log.wtf(TAG, "Failed to load resources", e); + } + return null; + } + + /** Retrieve assets held in the Safety Center resources APK. */ + @Override + public AssetManager getAssets() { + if (mAssetsFromApk == null) { + Context resourcesApkContext = getResourcesApkContext(); + if (resourcesApkContext != null) { + mAssetsFromApk = resourcesApkContext.getAssets(); + } + } + return mAssetsFromApk; + } + + /** Retrieve resources held in the Safety Center resources APK. */ + @Override + public Resources getResources() { + if (mResourcesFromApk == null) { + Context resourcesApkContext = getResourcesApkContext(); + if (resourcesApkContext != null) { + mResourcesFromApk = resourcesApkContext.getResources(); + } + } + return mResourcesFromApk; + } + + /** Retrieve theme held in the Safety Center resources APK. */ + @Override + public Resources.Theme getTheme() { + if (mThemeFromApk == null) { + Context resourcesApkContext = getResourcesApkContext(); + if (resourcesApkContext != null) { + mThemeFromApk = resourcesApkContext.getTheme(); + } + } + return mThemeFromApk; + } +} diff --git a/SafetyCenter/ResourcesLib/tests/Android.bp b/SafetyCenter/ResourcesLib/tests/Android.bp new file mode 100644 index 000000000..37770eb61 --- /dev/null +++ b/SafetyCenter/ResourcesLib/tests/Android.bp @@ -0,0 +1,38 @@ +// Copyright (C) 2022 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: ["Android-Apache-2.0"], +} + +android_test { + name: "SafetyCenterResourcesLibTests", + defaults: ["mts-target-sdk-version-current"], + sdk_version: "test_current", + min_sdk_version: "30", + srcs: [ + "java/**/*.kt", + ], + static_libs: [ + "safety-center-resources-lib", + "compatibility-device-util-axt", + ], + data: [ + ":SafetyCenterResourcesLibTestResources", + ], + test_suites: [ + "general-tests", + "mts-permission", + ], +} diff --git a/SafetyCenter/ResourcesLib/tests/AndroidManifest.xml b/SafetyCenter/ResourcesLib/tests/AndroidManifest.xml new file mode 100644 index 000000000..505505751 --- /dev/null +++ b/SafetyCenter/ResourcesLib/tests/AndroidManifest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2022 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="com.android.safetycenter.tests.resourceslib.safetycenterresourceslib"> + + <application android:label="Safety Center ResourcesLib Tests"> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.safetycenter.tests.resourceslib.safetycenterresourceslib" + android:label="Tests for the Safety Center ResourcesLib library" /> +</manifest> diff --git a/SafetyCenter/ResourcesLib/tests/AndroidTest.xml b/SafetyCenter/ResourcesLib/tests/AndroidTest.xml new file mode 100644 index 000000000..840f17d63 --- /dev/null +++ b/SafetyCenter/ResourcesLib/tests/AndroidTest.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2022 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 unit tests for the Safety Center ResourcesLib library."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + <option name="test-tag" value="SafetyCenterConfigTests" /> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" /> + + <!-- Install test and resources --> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="SafetyCenterResourcesLibTests.apk" /> + <option name="test-file-name" value="SafetyCenterResourcesLibTestResources.apk" /> + <option name="cleanup-apks" value="true" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.safetycenter.tests.resourceslib.safetycenterresourceslib" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + </test> +</configuration> diff --git a/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/Android.bp b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/Android.bp new file mode 100644 index 000000000..18628805d --- /dev/null +++ b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/Android.bp @@ -0,0 +1,26 @@ +// +// Copyright (C) 2022 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: ["Android-Apache-2.0"], +} + +android_test_helper_app { + name: "SafetyCenterResourcesLibTestResources", + defaults: ["mts-target-sdk-version-current"], + sdk_version: "test_current", + min_sdk_version: "30", +} diff --git a/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/AndroidManifest.xml b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/AndroidManifest.xml new file mode 100644 index 000000000..0af1e0d85 --- /dev/null +++ b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/AndroidManifest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 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="com.android.safetycenter.tests.config.safetycenterresourceslibtestresources"> + <application> + <!-- This is only used to identify this app by resolving the action. + The activity is never actually triggered. --> + <activity + android:name="android.app.Activity" + android:exported="true"> + <intent-filter> + <action android:name="com.android.safetycenter.tests.intent.action.SAFETY_CENTER_TEST_RESOURCES_APK" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/raw/test.txt b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/raw/test.txt new file mode 100644 index 000000000..3b1246497 --- /dev/null +++ b/SafetyCenter/ResourcesLib/tests/SafetyCenterResourcesLibTestResources/res/raw/test.txt @@ -0,0 +1 @@ +TEST
\ No newline at end of file diff --git a/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt b/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt new file mode 100644 index 000000000..b6fd732a6 --- /dev/null +++ b/SafetyCenter/ResourcesLib/tests/java/com/android/safetycenter/resources/SafetyCenterResourcesContextTest.kt @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2022 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 com.android.safetycenter.resources + +import android.content.Context +import android.content.pm.PackageManager +import androidx.test.core.app.ApplicationProvider.getApplicationContext +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SafetyCenterResourcesContextTest { + private val context: Context = getApplicationContext() + + @Test + fun validDataWithValidInputs() { + val safetyCenterResourcesContext = SafetyCenterResourcesContext( + context, + RESOURCES_APK_ACTION, + null, + CONFIG_NAME, + 0 + ) + assertThat(safetyCenterResourcesContext.resourcesApkPkgName).isEqualTo( + RESOURCES_APK_PKG_NAME + ) + val configContent = + safetyCenterResourcesContext.safetyCenterConfig?.bufferedReader().use { it?.readText() } + assertThat(configContent).isEqualTo(CONFIG_CONTENT) + assertNotNull(safetyCenterResourcesContext.assets) + assertNotNull(safetyCenterResourcesContext.resources) + assertNotNull(safetyCenterResourcesContext.theme) + } + + @Test + fun nullDataWithWrongAction() { + val safetyCenterResourcesContext = SafetyCenterResourcesContext( + context, + "wrong", + null, + CONFIG_NAME, + 0 + ) + assertNull(safetyCenterResourcesContext.resourcesApkPkgName) + assertNull(safetyCenterResourcesContext.safetyCenterConfig) + assertNull(safetyCenterResourcesContext.assets) + assertNull(safetyCenterResourcesContext.resources) + assertNull(safetyCenterResourcesContext.theme) + } + + @Test + fun nullDataWithWrongPath() { + val safetyCenterResourcesContext = SafetyCenterResourcesContext( + context, + RESOURCES_APK_ACTION, + "/apex/com.android.permission", + CONFIG_NAME, + 0 + ) + assertNull(safetyCenterResourcesContext.resourcesApkPkgName) + assertNull(safetyCenterResourcesContext.safetyCenterConfig) + assertNull(safetyCenterResourcesContext.assets) + assertNull(safetyCenterResourcesContext.resources) + assertNull(safetyCenterResourcesContext.theme) + } + + @Test + fun nullDataWithWrongFlag() { + val safetyCenterResourcesContext = SafetyCenterResourcesContext( + context, + RESOURCES_APK_ACTION, + null, + CONFIG_NAME, + PackageManager.MATCH_SYSTEM_ONLY + ) + assertNull(safetyCenterResourcesContext.resourcesApkPkgName) + assertNull(safetyCenterResourcesContext.safetyCenterConfig) + assertNull(safetyCenterResourcesContext.assets) + assertNull(safetyCenterResourcesContext.resources) + assertNull(safetyCenterResourcesContext.theme) + } + + @Test + fun nullConfigWithWrongConfigName() { + val safetyCenterResourcesContext = SafetyCenterResourcesContext( + context, + RESOURCES_APK_ACTION, + null, + "wrong", + 0 + ) + assertNotNull(safetyCenterResourcesContext.resourcesApkPkgName) + assertNull(safetyCenterResourcesContext.safetyCenterConfig) + assertNotNull(safetyCenterResourcesContext.assets) + assertNotNull(safetyCenterResourcesContext.resources) + assertNotNull(safetyCenterResourcesContext.theme) + } + + companion object { + const val RESOURCES_APK_ACTION = + "com.android.safetycenter.tests.intent.action.SAFETY_CENTER_TEST_RESOURCES_APK" + const val RESOURCES_APK_PKG_NAME = + "com.android.safetycenter.tests.config.safetycenterresourceslibtestresources" + const val CONFIG_NAME = "test" + const val CONFIG_CONTENT = "TEST" + } +}
\ No newline at end of file diff --git a/service/Android.bp b/service/Android.bp index 07b5d58a8..fcb7f6739 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -104,6 +104,8 @@ java_sdk_library { "kotlin-stdlib", "modules-utils-backgroundthread", "modules-utils-os", + "safety-center-config", + "safety-center-resources-lib", "service-permission-shared", ], exclude_kotlinc_generated_files: true, diff --git a/service/java/com/android/safetycenter/SafetyCenterService.java b/service/java/com/android/safetycenter/SafetyCenterService.java index 5b1cdcd9d..ff805f131 100644 --- a/service/java/com/android/safetycenter/SafetyCenterService.java +++ b/service/java/com/android/safetycenter/SafetyCenterService.java @@ -36,6 +36,7 @@ import android.safetycenter.ISafetyCenterManager; import android.safetycenter.SafetyCenterData; import android.safetycenter.SafetyCenterStatus; import android.safetycenter.SafetySourceData; +import android.util.Log; import androidx.annotation.Keep; import androidx.annotation.NonNull; @@ -43,8 +44,12 @@ import androidx.annotation.RequiresApi; import com.android.internal.annotations.GuardedBy; import com.android.permission.util.PermissionUtils; +import com.android.safetycenter.config.Parser; +import com.android.safetycenter.config.parser.SafetyCenterConfig; +import com.android.safetycenter.resources.SafetyCenterResourcesContext; import com.android.server.SystemService; +import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -59,16 +64,19 @@ import java.util.Objects; @Keep @RequiresApi(TIRAMISU) public final class SafetyCenterService extends SystemService { + private static final String TAG = "SafetyCenterService"; /** Phenotype flag that determines whether SafetyCenter is enabled. */ private static final String PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled"; @NonNull private final Object mLock = new Object(); - // TODO(b/206789604): Use persistent storage instead. + // TODO(b/202386571): Create a new data model to store both config and dynamic data in memory. @GuardedBy("mLock") @NonNull private final Map<Key, SafetySourceData> mSafetySourceDataForKey = new HashMap<>(); + @Nullable + private SafetyCenterConfig mSafetyCenterConfig; @NonNull private final AppOpsManager mAppOpsManager; @@ -77,14 +85,41 @@ public final class SafetyCenterService extends SystemService { private final List<IOnSafetyCenterDataChangedListener> mSafetyCenterDataChangedListeners = new ArrayList<>(); + @NonNull + private final SafetyCenterResourcesContext mSafetyCenterResourcesContext; + public SafetyCenterService(@NonNull Context context) { super(context); mAppOpsManager = requireNonNull(context.getSystemService(AppOpsManager.class)); + mSafetyCenterResourcesContext = new SafetyCenterResourcesContext(context); } @Override public void onStart() { publishBinderService(Context.SAFETY_CENTER_SERVICE, new Stub()); + readSafetyCenterConfig(); + } + + private void readSafetyCenterConfig() { + // TODO(b/214568975): Decide if we should disable Safety Center if there is a problem + // reading the config. + String resoursePkgName = mSafetyCenterResourcesContext.getResourcesApkPkgName(); + if (resoursePkgName == null) { + Log.e(TAG, "Cannot get Safety Center resources"); + return; + } + InputStream in = mSafetyCenterResourcesContext.getSafetyCenterConfig(); + if (in == null) { + Log.e(TAG, "Cannot get Safety Center config"); + return; + } + try { + mSafetyCenterConfig = Parser.parse(in, resoursePkgName, + mSafetyCenterResourcesContext.getResources()); + Log.i(TAG, "Safety Center config read successfully"); + } catch (Parser.ParseException e) { + Log.e(TAG, "Cannot read Safety Center config", e); + } } private static final class Key { |