diff options
185 files changed, 4533 insertions, 2616 deletions
diff --git a/Android.bp b/Android.bp index 69d654fbddbc..f63e78bedd43 100644 --- a/Android.bp +++ b/Android.bp @@ -445,13 +445,6 @@ filegroup { } filegroup { - name: "graphicsstats_proto", - srcs: [ - "libs/hwui/protos/graphicsstats.proto", - ], -} - -filegroup { name: "libvibrator_aidl", srcs: [ "core/java/android/os/IExternalVibrationController.aidl", diff --git a/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java b/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java deleted file mode 100644 index 236f548cf6dd..000000000000 --- a/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2017 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.os; - -import android.content.ComponentName; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.perftests.utils.BenchmarkState; -import android.perftests.utils.PerfStatusReporter; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.LargeTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@LargeTest -public class PackageManagerPerfTest { - private static final String PERMISSION_NAME_EXISTS = - "com.android.perftests.core.TestPermission"; - private static final String PERMISSION_NAME_DOESNT_EXIST = - "com.android.perftests.core.TestBadPermission"; - private static final ComponentName TEST_ACTIVITY = - new ComponentName("com.android.perftests.core", - "android.perftests.utils.PerfTestActivity"); - - @Rule - public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - - @Test - public void testCheckPermissionExists() { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager(); - final String packageName = TEST_ACTIVITY.getPackageName(); - - while (state.keepRunning()) { - int ret = pm.checkPermission(PERMISSION_NAME_EXISTS, packageName); - } - } - - @Test - public void testCheckPermissionDoesntExist() { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager(); - final String packageName = TEST_ACTIVITY.getPackageName(); - - while (state.keepRunning()) { - int ret = pm.checkPermission(PERMISSION_NAME_DOESNT_EXIST, packageName); - } - } - - @Test - public void testQueryIntentActivities() { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager(); - final Intent intent = new Intent("com.android.perftests.core.PERFTEST"); - - while (state.keepRunning()) { - pm.queryIntentActivities(intent, 0); - } - } - - @Test - public void testGetPackageInfo() throws Exception { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager(); - final String packageName = TEST_ACTIVITY.getPackageName(); - - while (state.keepRunning()) { - pm.getPackageInfo(packageName, 0); - } - } - - @Test - public void testGetApplicationInfo() throws Exception { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager(); - final String packageName = TEST_ACTIVITY.getPackageName(); - - while (state.keepRunning()) { - pm.getApplicationInfo(packageName, 0); - } - } - - @Test - public void testGetActivityInfo() throws Exception { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager(); - - while (state.keepRunning()) { - pm.getActivityInfo(TEST_ACTIVITY, 0); - } - } -} diff --git a/apct-tests/perftests/packagemanager/Android.bp b/apct-tests/perftests/packagemanager/Android.bp new file mode 100644 index 000000000000..17033e048c7d --- /dev/null +++ b/apct-tests/perftests/packagemanager/Android.bp @@ -0,0 +1,21 @@ +android_test { + name: "PackageManagerPerfTests", + + srcs: ["src/**/*.java"], + + static_libs: [ + "platform-compat-test-rules", + "androidx.appcompat_appcompat", + "androidx.test.rules", + "androidx.test.ext.junit", + "androidx.annotation_annotation", + "apct-perftests-utils", + ], + + libs: ["android.test.base"], + + platform_apis: true, + + test_suites: ["device-tests"], + +} diff --git a/apct-tests/perftests/packagemanager/AndroidManifest.xml b/apct-tests/perftests/packagemanager/AndroidManifest.xml new file mode 100644 index 000000000000..520f4b55d931 --- /dev/null +++ b/apct-tests/perftests/packagemanager/AndroidManifest.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 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.perftests.packagemanager"> + + <permission android:name="com.android.perftests.packagemanager.TestPermission" /> + <uses-permission android:name="com.android.perftests.packagemanager.TestPermission" /> + + <queries> + <package android:name="com.android.perftests.appenumeration0" /> + <package android:name="com.android.perftests.appenumeration1" /> + <package android:name="com.android.perftests.appenumeration2" /> + <package android:name="com.android.perftests.appenumeration3" /> + <package android:name="com.android.perftests.appenumeration4" /> + <package android:name="com.android.perftests.appenumeration5" /> + <package android:name="com.android.perftests.appenumeration6" /> + <package android:name="com.android.perftests.appenumeration7" /> + <package android:name="com.android.perftests.appenumeration8" /> + <package android:name="com.android.perftests.appenumeration9" /> + <package android:name="com.android.perftests.appenumeration10" /> + <package android:name="com.android.perftests.appenumeration11" /> + <package android:name="com.android.perftests.appenumeration12" /> + <package android:name="com.android.perftests.appenumeration13" /> + <package android:name="com.android.perftests.appenumeration14" /> + <package android:name="com.android.perftests.appenumeration15" /> + <package android:name="com.android.perftests.appenumeration16" /> + <package android:name="com.android.perftests.appenumeration17" /> + <package android:name="com.android.perftests.appenumeration18" /> + <package android:name="com.android.perftests.appenumeration19" /> + <package android:name="com.android.perftests.appenumeration20" /> + <package android:name="com.android.perftests.appenumeration21" /> + <package android:name="com.android.perftests.appenumeration22" /> + <package android:name="com.android.perftests.appenumeration23" /> + <package android:name="com.android.perftests.appenumeration24" /> + <package android:name="com.android.perftests.appenumeration25" /> + <package android:name="com.android.perftests.appenumeration26" /> + <package android:name="com.android.perftests.appenumeration27" /> + <package android:name="com.android.perftests.appenumeration28" /> + <package android:name="com.android.perftests.appenumeration29" /> + <package android:name="com.android.perftests.appenumeration30" /> + <package android:name="com.android.perftests.appenumeration31" /> + <package android:name="com.android.perftests.appenumeration32" /> + <package android:name="com.android.perftests.appenumeration33" /> + <package android:name="com.android.perftests.appenumeration34" /> + <package android:name="com.android.perftests.appenumeration35" /> + <package android:name="com.android.perftests.appenumeration36" /> + <package android:name="com.android.perftests.appenumeration37" /> + <package android:name="com.android.perftests.appenumeration38" /> + <package android:name="com.android.perftests.appenumeration39" /> + <package android:name="com.android.perftests.appenumeration40" /> + <package android:name="com.android.perftests.appenumeration41" /> + <package android:name="com.android.perftests.appenumeration42" /> + <package android:name="com.android.perftests.appenumeration43" /> + <package android:name="com.android.perftests.appenumeration44" /> + <package android:name="com.android.perftests.appenumeration45" /> + <package android:name="com.android.perftests.appenumeration46" /> + <package android:name="com.android.perftests.appenumeration47" /> + <package android:name="com.android.perftests.appenumeration48" /> + <package android:name="com.android.perftests.appenumeration49" /> + </queries> + + <application> + <uses-library android:name="android.test.runner" /> + <activity android:name="android.perftests.utils.PerfTestActivity"> + <intent-filter> + <action android:name="com.android.perftests.packagemanager.PERFTEST" /> + </intent-filter> + </activity> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.perftests.packagemanager"/> + +</manifest> diff --git a/apct-tests/perftests/packagemanager/AndroidTest.xml b/apct-tests/perftests/packagemanager/AndroidTest.xml new file mode 100644 index 000000000000..c112d87d83e1 --- /dev/null +++ b/apct-tests/perftests/packagemanager/AndroidTest.xml @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 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 PackageManagerPerfTests metric instrumentation."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-metric-instrumentation" /> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="PackageManagerPerfTests.apk" /> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="force-queryable" value="false" /> + <option name="test-file-name" value="QueriesAll0.apk" /> + <option name="test-file-name" value="QueriesAll1.apk" /> + <option name="test-file-name" value="QueriesAll2.apk" /> + <option name="test-file-name" value="QueriesAll3.apk" /> + <option name="test-file-name" value="QueriesAll4.apk" /> + <option name="test-file-name" value="QueriesAll5.apk" /> + <option name="test-file-name" value="QueriesAll6.apk" /> + <option name="test-file-name" value="QueriesAll7.apk" /> + <option name="test-file-name" value="QueriesAll8.apk" /> + <option name="test-file-name" value="QueriesAll9.apk" /> + <option name="test-file-name" value="QueriesAll10.apk" /> + <option name="test-file-name" value="QueriesAll11.apk" /> + <option name="test-file-name" value="QueriesAll12.apk" /> + <option name="test-file-name" value="QueriesAll13.apk" /> + <option name="test-file-name" value="QueriesAll14.apk" /> + <option name="test-file-name" value="QueriesAll15.apk" /> + <option name="test-file-name" value="QueriesAll16.apk" /> + <option name="test-file-name" value="QueriesAll17.apk" /> + <option name="test-file-name" value="QueriesAll18.apk" /> + <option name="test-file-name" value="QueriesAll19.apk" /> + <option name="test-file-name" value="QueriesAll20.apk" /> + <option name="test-file-name" value="QueriesAll21.apk" /> + <option name="test-file-name" value="QueriesAll22.apk" /> + <option name="test-file-name" value="QueriesAll23.apk" /> + <option name="test-file-name" value="QueriesAll24.apk" /> + <option name="test-file-name" value="QueriesAll25.apk" /> + <option name="test-file-name" value="QueriesAll26.apk" /> + <option name="test-file-name" value="QueriesAll27.apk" /> + <option name="test-file-name" value="QueriesAll28.apk" /> + <option name="test-file-name" value="QueriesAll29.apk" /> + <option name="test-file-name" value="QueriesAll30.apk" /> + <option name="test-file-name" value="QueriesAll31.apk" /> + <option name="test-file-name" value="QueriesAll32.apk" /> + <option name="test-file-name" value="QueriesAll33.apk" /> + <option name="test-file-name" value="QueriesAll34.apk" /> + <option name="test-file-name" value="QueriesAll35.apk" /> + <option name="test-file-name" value="QueriesAll36.apk" /> + <option name="test-file-name" value="QueriesAll37.apk" /> + <option name="test-file-name" value="QueriesAll38.apk" /> + <option name="test-file-name" value="QueriesAll39.apk" /> + <option name="test-file-name" value="QueriesAll40.apk" /> + <option name="test-file-name" value="QueriesAll41.apk" /> + <option name="test-file-name" value="QueriesAll42.apk" /> + <option name="test-file-name" value="QueriesAll43.apk" /> + <option name="test-file-name" value="QueriesAll44.apk" /> + <option name="test-file-name" value="QueriesAll45.apk" /> + <option name="test-file-name" value="QueriesAll46.apk" /> + <option name="test-file-name" value="QueriesAll47.apk" /> + <option name="test-file-name" value="QueriesAll48.apk" /> + <option name="test-file-name" value="QueriesAll49.apk" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.perftests.packagemanager" /> + <option name="hidden-api-checks" value="false"/> + </test> + + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="directory-keys" value="/data/local/PackageManagerPerfTests" /> + <option name="collect-on-run-ended-only" value="true" /> + </metrics_collector> +</configuration> diff --git a/apct-tests/perftests/packagemanager/apps/query-all/Android.bp b/apct-tests/perftests/packagemanager/apps/query-all/Android.bp new file mode 100644 index 000000000000..3cb1589bc376 --- /dev/null +++ b/apct-tests/perftests/packagemanager/apps/query-all/Android.bp @@ -0,0 +1,314 @@ +// Copyright (C) 2020 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: "QueriesAll0", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration0", + ] +} +android_test_helper_app { + name: "QueriesAll1", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration1", + ] +} +android_test_helper_app { + name: "QueriesAll2", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration2", + ] +} +android_test_helper_app { + name: "QueriesAll3", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration3", + ] +} +android_test_helper_app { + name: "QueriesAll4", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration4", + ] +} +android_test_helper_app { + name: "QueriesAll5", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration5", + ] +} +android_test_helper_app { + name: "QueriesAll6", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration6", + ] +} +android_test_helper_app { + name: "QueriesAll7", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration7", + ] +} +android_test_helper_app { + name: "QueriesAll8", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration8", + ] +} +android_test_helper_app { + name: "QueriesAll9", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration9", + ] +} +android_test_helper_app { + name: "QueriesAll10", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration10", + ] +} +android_test_helper_app { + name: "QueriesAll11", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration11", + ] +} +android_test_helper_app { + name: "QueriesAll12", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration12", + ] +} +android_test_helper_app { + name: "QueriesAll13", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration13", + ] +} +android_test_helper_app { + name: "QueriesAll14", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration14", + ] +} +android_test_helper_app { + name: "QueriesAll15", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration15", + ] +} +android_test_helper_app { + name: "QueriesAll16", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration16", + ] +} +android_test_helper_app { + name: "QueriesAll17", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration17", + ] +} +android_test_helper_app { + name: "QueriesAll18", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration18", + ] +} +android_test_helper_app { + name: "QueriesAll19", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration19", + ] +} +android_test_helper_app { + name: "QueriesAll20", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration20", + ] +} +android_test_helper_app { + name: "QueriesAll21", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration21", + ] +} +android_test_helper_app { + name: "QueriesAll22", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration22", + ] +} +android_test_helper_app { + name: "QueriesAll23", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration23", + ] +} +android_test_helper_app { + name: "QueriesAll24", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration24", + ] +} +android_test_helper_app { + name: "QueriesAll25", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration25", + ] +} +android_test_helper_app { + name: "QueriesAll26", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration26", + ] +} +android_test_helper_app { + name: "QueriesAll27", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration27", + ] +} +android_test_helper_app { + name: "QueriesAll28", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration28", + ] +} +android_test_helper_app { + name: "QueriesAll29", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration29", + ] +} +android_test_helper_app { + name: "QueriesAll30", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration30", + ] +} +android_test_helper_app { + name: "QueriesAll31", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration31", + ] +} +android_test_helper_app { + name: "QueriesAll32", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration32", + ] +} +android_test_helper_app { + name: "QueriesAll33", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration33", + ] +} +android_test_helper_app { + name: "QueriesAll34", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration34", + ] +} +android_test_helper_app { + name: "QueriesAll35", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration35", + ] +} +android_test_helper_app { + name: "QueriesAll36", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration36", + ] +} +android_test_helper_app { + name: "QueriesAll37", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration37", + ] +} +android_test_helper_app { + name: "QueriesAll38", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration38", + ] +} +android_test_helper_app { + name: "QueriesAll39", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration39", + ] +} +android_test_helper_app { + name: "QueriesAll40", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration40", + ] +} +android_test_helper_app { + name: "QueriesAll41", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration41", + ] +} +android_test_helper_app { + name: "QueriesAll42", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration42", + ] +} +android_test_helper_app { + name: "QueriesAll43", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration43", + ] +} +android_test_helper_app { + name: "QueriesAll44", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration44", + ] +} +android_test_helper_app { + name: "QueriesAll45", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration45", + ] +} +android_test_helper_app { + name: "QueriesAll46", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration46", + ] +} +android_test_helper_app { + name: "QueriesAll47", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration47", + ] +} +android_test_helper_app { + name: "QueriesAll48", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration48", + ] +} +android_test_helper_app { + name: "QueriesAll49", + aaptflags: [ + "--rename-manifest-package com.android.perftests.appenumeration49", + ] +} diff --git a/apct-tests/perftests/packagemanager/apps/query-all/AndroidManifest.xml b/apct-tests/perftests/packagemanager/apps/query-all/AndroidManifest.xml new file mode 100644 index 000000000000..e2cfa0430a32 --- /dev/null +++ b/apct-tests/perftests/packagemanager/apps/query-all/AndroidManifest.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 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.perftests.appenumeration"> + + <application android:hasCode="false" > + <activity android:name="android.perftests.utils.PerfTestActivity"> + <intent-filter> + <action android:name="com.android.perftests.packagemanager.PERFTEST" /> + </intent-filter> + </activity> + </application> + + <queries> + <package android:name="com.android.perftests.appenumeration0" /> + <package android:name="com.android.perftests.appenumeration1" /> + <package android:name="com.android.perftests.appenumeration2" /> + <package android:name="com.android.perftests.appenumeration3" /> + <package android:name="com.android.perftests.appenumeration4" /> + <package android:name="com.android.perftests.appenumeration5" /> + <package android:name="com.android.perftests.appenumeration6" /> + <package android:name="com.android.perftests.appenumeration7" /> + <package android:name="com.android.perftests.appenumeration8" /> + <package android:name="com.android.perftests.appenumeration9" /> + <package android:name="com.android.perftests.appenumeration10" /> + <package android:name="com.android.perftests.appenumeration11" /> + <package android:name="com.android.perftests.appenumeration12" /> + <package android:name="com.android.perftests.appenumeration13" /> + <package android:name="com.android.perftests.appenumeration14" /> + <package android:name="com.android.perftests.appenumeration15" /> + <package android:name="com.android.perftests.appenumeration16" /> + <package android:name="com.android.perftests.appenumeration17" /> + <package android:name="com.android.perftests.appenumeration18" /> + <package android:name="com.android.perftests.appenumeration19" /> + <package android:name="com.android.perftests.appenumeration20" /> + <package android:name="com.android.perftests.appenumeration21" /> + <package android:name="com.android.perftests.appenumeration22" /> + <package android:name="com.android.perftests.appenumeration23" /> + <package android:name="com.android.perftests.appenumeration24" /> + <package android:name="com.android.perftests.appenumeration25" /> + <package android:name="com.android.perftests.appenumeration26" /> + <package android:name="com.android.perftests.appenumeration27" /> + <package android:name="com.android.perftests.appenumeration28" /> + <package android:name="com.android.perftests.appenumeration29" /> + <package android:name="com.android.perftests.appenumeration30" /> + <package android:name="com.android.perftests.appenumeration31" /> + <package android:name="com.android.perftests.appenumeration32" /> + <package android:name="com.android.perftests.appenumeration33" /> + <package android:name="com.android.perftests.appenumeration34" /> + <package android:name="com.android.perftests.appenumeration35" /> + <package android:name="com.android.perftests.appenumeration36" /> + <package android:name="com.android.perftests.appenumeration37" /> + <package android:name="com.android.perftests.appenumeration38" /> + <package android:name="com.android.perftests.appenumeration39" /> + <package android:name="com.android.perftests.appenumeration40" /> + <package android:name="com.android.perftests.appenumeration41" /> + <package android:name="com.android.perftests.appenumeration42" /> + <package android:name="com.android.perftests.appenumeration43" /> + <package android:name="com.android.perftests.appenumeration44" /> + <package android:name="com.android.perftests.appenumeration45" /> + <package android:name="com.android.perftests.appenumeration46" /> + <package android:name="com.android.perftests.appenumeration47" /> + <package android:name="com.android.perftests.appenumeration48" /> + <package android:name="com.android.perftests.appenumeration49" /> + </queries> + +</manifest>
\ No newline at end of file diff --git a/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java b/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java new file mode 100644 index 000000000000..d7428cf0ab8a --- /dev/null +++ b/apct-tests/perftests/packagemanager/src/android/os/PackageManagerPerfTest.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2020 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.os; + +import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; +import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + +import android.compat.testing.PlatformCompatChangeRule; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.LargeTest; +import androidx.test.platform.app.InstrumentationRegistry; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class PackageManagerPerfTest { + private static final String PERMISSION_NAME_EXISTS = + "com.android.perftests.packagemanager.TestPermission"; + private static final String PERMISSION_NAME_DOESNT_EXIST = + "com.android.perftests.packagemanager.TestBadPermission"; + private static final String OTHER_PACKAGE_NAME = "com.android.perftests.appenumeration0"; + private static final ComponentName TEST_ACTIVITY = + new ComponentName(OTHER_PACKAGE_NAME, + "android.perftests.utils.PerfTestActivity"); + + @Rule + public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @Rule + public final PlatformCompatChangeRule mPlatformCompatChangeRule = + new PlatformCompatChangeRule(); + + public PackageManagerPerfTest() throws PackageManager.NameNotFoundException { + final Context context = InstrumentationRegistry.getInstrumentation().getContext(); + } + + @Test + @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testCheckPermissionExists() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager(); + final String packageName = TEST_ACTIVITY.getPackageName(); + + while (state.keepRunning()) { + int ret = pm.checkPermission(PERMISSION_NAME_EXISTS, packageName); + } + } + + @Test + @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testCheckPermissionExistsWithFiltering() { + testCheckPermissionExists(); + } + + @Test + @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testCheckPermissionDoesntExist() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager(); + final String packageName = TEST_ACTIVITY.getPackageName(); + + while (state.keepRunning()) { + int ret = pm.checkPermission(PERMISSION_NAME_DOESNT_EXIST, packageName); + } + } + + @Test + @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testCheckPermissionDoesntExistWithFiltering() { + testCheckPermissionDoesntExist(); + } + + @Test + @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testQueryIntentActivities() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager(); + final Intent intent = new Intent("com.android.perftests.core.PERFTEST"); + + while (state.keepRunning()) { + pm.queryIntentActivities(intent, 0); + } + } + + @Test + @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testQueryIntentActivitiesWithFiltering() { + testQueryIntentActivities(); + } + + @Test + @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testGetPackageInfo() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager(); + + while (state.keepRunning()) { + pm.getPackageInfo(OTHER_PACKAGE_NAME, 0); + } + } + + @Test + @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testGetPackageInfoWithFiltering() throws Exception { + testGetPackageInfo(); + } + + @Test + @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testGetApplicationInfo() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager(); + + while (state.keepRunning()) { + pm.getApplicationInfo(OTHER_PACKAGE_NAME, 0); + } + } + + @Test + @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testGetApplicationInfoWithFiltering() throws Exception { + testGetApplicationInfo(); + } + + @Test + @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testGetActivityInfo() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager(); + + while (state.keepRunning()) { + pm.getActivityInfo(TEST_ACTIVITY, 0); + } + } + + @Test + @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testGetActivityInfoWithFiltering() throws Exception { + testGetActivityInfo(); + } + + @Test + @DisableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testGetInstalledPackages() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final PackageManager pm = + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageManager(); + + while (state.keepRunning()) { + pm.getInstalledPackages(0); + } + } + + @Test + @EnableCompatChanges(PackageManager.FILTER_APPLICATION_QUERY) + public void testGetInstalledPackagesWithFiltering() throws Exception { + testGetInstalledPackages(); + } +} diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 69f4748548a7..939164edd13e 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -494,9 +494,10 @@ public class JobSchedulerService extends com.android.server.SystemService private static final String DEPRECATED_KEY_BG_LOW_JOB_COUNT = "bg_low_job_count"; private static final String DEPRECATED_KEY_BG_CRITICAL_JOB_COUNT = "bg_critical_job_count"; - private static final String KEY_MAX_STANDARD_RESCHEDULE_COUNT + private static final String DEPRECATED_KEY_MAX_STANDARD_RESCHEDULE_COUNT = "max_standard_reschedule_count"; - private static final String KEY_MAX_WORK_RESCHEDULE_COUNT = "max_work_reschedule_count"; + private static final String DEPRECATED_KEY_MAX_WORK_RESCHEDULE_COUNT = + "max_work_reschedule_count"; private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time"; private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time"; private static final String DEPRECATED_KEY_STANDBY_HEARTBEAT_TIME = @@ -525,8 +526,6 @@ public class JobSchedulerService extends com.android.server.SystemService private static final long DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = 31 * MINUTE_IN_MILLIS; private static final float DEFAULT_HEAVY_USE_FACTOR = .9f; private static final float DEFAULT_MODERATE_USE_FACTOR = .5f; - private static final int DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT = Integer.MAX_VALUE; - private static final int DEFAULT_MAX_WORK_RESCHEDULE_COUNT = Integer.MAX_VALUE; private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS; private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS; private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f; @@ -640,16 +639,6 @@ public class JobSchedulerService extends com.android.server.SystemService "screen_off_job_concurrency_increase_delay_ms", 30_000); /** - * The maximum number of times we allow a job to have itself rescheduled before - * giving up on it, for standard jobs. - */ - int MAX_STANDARD_RESCHEDULE_COUNT = DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT; - /** - * The maximum number of times we allow a job to have itself rescheduled before - * giving up on it, for jobs that are executing work. - */ - int MAX_WORK_RESCHEDULE_COUNT = DEFAULT_MAX_WORK_RESCHEDULE_COUNT; - /** * The minimum backoff time to allow for linear backoff. */ long MIN_LINEAR_BACKOFF_TIME = DEFAULT_MIN_LINEAR_BACKOFF_TIME; @@ -735,10 +724,6 @@ public class JobSchedulerService extends com.android.server.SystemService SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.parse(mParser); - MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT, - DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT); - MAX_WORK_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_WORK_RESCHEDULE_COUNT, - DEFAULT_MAX_WORK_RESCHEDULE_COUNT); MIN_LINEAR_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_LINEAR_BACKOFF_TIME, DEFAULT_MIN_LINEAR_BACKOFF_TIME); MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME, @@ -790,8 +775,6 @@ public class JobSchedulerService extends com.android.server.SystemService SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.dump(pw, ""); - pw.printPair(KEY_MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT).println(); - pw.printPair(KEY_MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT).println(); pw.printPair(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println(); pw.printPair(KEY_MIN_EXP_BACKOFF_TIME, MIN_EXP_BACKOFF_TIME).println(); pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println(); @@ -827,8 +810,6 @@ public class JobSchedulerService extends com.android.server.SystemService SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.dumpProto(proto, ConstantsProto.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS); - proto.write(ConstantsProto.MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT); - proto.write(ConstantsProto.MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT); proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME); proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME); proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC); @@ -1390,18 +1371,8 @@ public class JobSchedulerService extends com.android.server.SystemService // Effective standby bucket can change after this in some situations so use // the real bucket so that the job is tracked by the controllers. if (js.getStandbyBucket() == RESTRICTED_INDEX) { - js.addDynamicConstraint(JobStatus.CONSTRAINT_BATTERY_NOT_LOW); - js.addDynamicConstraint(JobStatus.CONSTRAINT_CHARGING); - js.addDynamicConstraint(JobStatus.CONSTRAINT_CONNECTIVITY); - js.addDynamicConstraint(JobStatus.CONSTRAINT_IDLE); - mRestrictiveControllers.get(j).startTrackingRestrictedJobLocked(js); } else { - js.removeDynamicConstraint(JobStatus.CONSTRAINT_BATTERY_NOT_LOW); - js.removeDynamicConstraint(JobStatus.CONSTRAINT_CHARGING); - js.removeDynamicConstraint(JobStatus.CONSTRAINT_CONNECTIVITY); - js.removeDynamicConstraint(JobStatus.CONSTRAINT_IDLE); - mRestrictiveControllers.get(j).stopTrackingRestrictedJobLocked(js); } } @@ -1738,19 +1709,6 @@ public class JobSchedulerService extends com.android.server.SystemService final int backoffAttempts = failureToReschedule.getNumFailures() + 1; long delayMillis; - if (failureToReschedule.hasWorkLocked()) { - if (backoffAttempts > mConstants.MAX_WORK_RESCHEDULE_COUNT) { - Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #" - + backoffAttempts + " > work limit " - + mConstants.MAX_STANDARD_RESCHEDULE_COUNT); - return null; - } - } else if (backoffAttempts > mConstants.MAX_STANDARD_RESCHEDULE_COUNT) { - Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #" - + backoffAttempts + " > std limit " + mConstants.MAX_STANDARD_RESCHEDULE_COUNT); - return null; - } - switch (job.getBackoffPolicy()) { case JobInfo.BACKOFF_POLICY_LINEAR: { long backoff = initialBackoffMillis; diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index f706260edec2..1e89158ca4bb 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -17,6 +17,8 @@ package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX; +import static com.android.server.job.JobSchedulerService.NEVER_INDEX; +import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.app.AppGlobals; @@ -63,26 +65,36 @@ import java.util.function.Predicate; * @hide */ public final class JobStatus { - static final String TAG = "JobSchedulerService"; + private static final String TAG = "JobScheduler.JobStatus"; static final boolean DEBUG = JobSchedulerService.DEBUG; public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE; public static final long NO_EARLIEST_RUNTIME = 0L; - public static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING; // 1 < 0 - public static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE; // 1 << 2 - public static final int CONSTRAINT_BATTERY_NOT_LOW = - JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW; // 1 << 1 + static final int CONSTRAINT_CHARGING = JobInfo.CONSTRAINT_FLAG_CHARGING; // 1 < 0 + static final int CONSTRAINT_IDLE = JobInfo.CONSTRAINT_FLAG_DEVICE_IDLE; // 1 << 2 + static final int CONSTRAINT_BATTERY_NOT_LOW = JobInfo.CONSTRAINT_FLAG_BATTERY_NOT_LOW; // 1 << 1 static final int CONSTRAINT_STORAGE_NOT_LOW = JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW; // 1 << 3 static final int CONSTRAINT_TIMING_DELAY = 1<<31; static final int CONSTRAINT_DEADLINE = 1<<30; - public static final int CONSTRAINT_CONNECTIVITY = 1 << 28; + static final int CONSTRAINT_CONNECTIVITY = 1 << 28; static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26; static final int CONSTRAINT_DEVICE_NOT_DOZING = 1 << 25; // Implicit constraint static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24; // Implicit constraint static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint /** + * The additional set of dynamic constraints that must be met if the job's effective bucket is + * {@link JobSchedulerService#RESTRICTED_INDEX}. Connectivity can be ignored if the job doesn't + * need network. + */ + private static final int DYNAMIC_RESTRICTED_CONSTRAINTS = + CONSTRAINT_BATTERY_NOT_LOW + | CONSTRAINT_CHARGING + | CONSTRAINT_CONNECTIVITY + | CONSTRAINT_IDLE; + + /** * The constraints that we want to log to statsd. * * Constraints that can be inferred from other atoms have been excluded to avoid logging too @@ -419,7 +431,11 @@ public final class JobStatus { this.requiredConstraints = requiredConstraints; mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST; mReadyNotDozing = (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; - mReadyDynamicSatisfied = true; + if (standbyBucket == RESTRICTED_INDEX) { + addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS); + } else { + mReadyDynamicSatisfied = true; + } mLastSuccessfulRunTime = lastSuccessfulRunTime; mLastFailedRunTime = lastFailedRunTime; @@ -727,6 +743,14 @@ public final class JobStatus { } public void setStandbyBucket(int newBucket) { + if (newBucket == RESTRICTED_INDEX) { + // Adding to the bucket. + addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS); + } else if (standbyBucket == RESTRICTED_INDEX) { + // Removing from the RESTRICTED bucket. + removeDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS); + } + standbyBucket = newBucket; } @@ -1054,6 +1078,11 @@ public final class JobStatus { if (old == state) { return false; } + if (DEBUG) { + Slog.v(TAG, + "Constraint " + constraint + " is " + (!state ? "NOT " : "") + "satisfied for " + + toShortString()); + } satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0); mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST; mReadyDynamicSatisfied = @@ -1086,38 +1115,40 @@ public final class JobStatus { } /** - * Indicates that this job cannot run without the specified constraint. This is evaluated + * Indicates that this job cannot run without the specified constraints. This is evaluated * separately from the job's explicitly requested constraints and MUST be satisfied before * the job can run if the app doesn't have quota. - * */ - public void addDynamicConstraint(int constraint) { - if (constraint == CONSTRAINT_WITHIN_QUOTA) { + private void addDynamicConstraints(int constraints) { + if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) { + // Quota should never be used as a dynamic constraint. Slog.wtf(TAG, "Tried to set quota as a dynamic constraint"); - return; + constraints &= ~CONSTRAINT_WITHIN_QUOTA; } // Connectivity and content trigger are special since they're only valid to add if the // job has requested network or specific content URIs. Adding these constraints to jobs // that don't need them doesn't make sense. - if ((constraint == CONSTRAINT_CONNECTIVITY && !hasConnectivityConstraint()) - || (constraint == CONSTRAINT_CONTENT_TRIGGER && !hasContentTriggerConstraint())) { - return; + if (!hasConnectivityConstraint()) { + constraints &= ~CONSTRAINT_CONNECTIVITY; + } + if (!hasContentTriggerConstraint()) { + constraints &= ~CONSTRAINT_CONTENT_TRIGGER; } - mDynamicConstraints |= constraint; + mDynamicConstraints |= constraints; mReadyDynamicSatisfied = mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints); } /** - * Removes a dynamic constraint from a job, meaning that the requirement is not required for + * Removes dynamic constraints from a job, meaning that the requirements are not required for * the job to run (if the job itself hasn't requested the constraint. This is separate from * the job's explicitly requested constraints and does not remove those requested constraints. * */ - public void removeDynamicConstraint(int constraint) { - mDynamicConstraints &= ~constraint; + private void removeDynamicConstraints(int constraints) { + mDynamicConstraints &= ~constraints; mReadyDynamicSatisfied = mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints); } @@ -1193,7 +1224,11 @@ public final class JobStatus { private boolean isReady(int satisfiedConstraints) { // Quota and dynamic constraints trump all other constraints. - if (!mReadyWithinQuota && !mReadyDynamicSatisfied) { + // NEVER jobs are not supposed to run at all. Since we're using quota to allow parole + // sessions (exempt from dynamic restrictions), we need the additional check to ensure + // that NEVER jobs don't run. + // TODO: cleanup quota and standby bucket management so we don't need the additional checks + if ((!mReadyWithinQuota && !mReadyDynamicSatisfied) || standbyBucket == NEVER_INDEX) { return false; } // Deadline constraint trumps other constraints besides quota and dynamic (except for diff --git a/apex/permission/testing/Android.bp b/apex/permission/testing/Android.bp index f8978dcd83ee..63bf0a08e956 100644 --- a/apex/permission/testing/Android.bp +++ b/apex/permission/testing/Android.bp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -apex { +apex_test { name: "test_com.android.permission", visibility: [ "//system/apex/tests", diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableViewController.java b/apex/sdkextensions/framework/java/android/os/ext/test/Test.java index e14ca8c4e590..1715f498be1e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableViewController.java +++ b/apex/sdkextensions/framework/java/android/os/ext/test/Test.java @@ -14,24 +14,40 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.row; +package android.os.ext.test; -import javax.inject.Inject; +import android.annotation.SystemApi; /** - * Controller for {@link ExpandableView}. + * This class exists temporarily to verify SDK updates are working properly. + * @deprecated Do not use. */ -public class ExpandableViewController { - private final ExpandableView mView; - - @Inject - public ExpandableViewController(ExpandableView view) { - mView = view; - } - - /** - * Initialize the controller. - */ - public void init() { - } +@Deprecated +public class Test { + + public Test() { } + + /** @hide */ + public void testA() {} + + /** @hide */ + public void testB() {} + + /** @hide */ + public void testC() {} + + /** @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public void testD() {} + + public void testE() {} + + /** @hide */ + @SystemApi + public void testF() {} + + /** @hide */ + @SystemApi + public void testG() {} + } diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp index 6d639fddd043..db5f439cd40e 100644 --- a/apex/statsd/aidl/Android.bp +++ b/apex/statsd/aidl/Android.bp @@ -13,35 +13,31 @@ // See the License for the specific language governing permissions and // limitations under the License. // - -// TODO(b/145815909): move StatsDimensionsValue.aidl here filegroup { - name: "statsd_aidl", + name: "statsd_java_aidl", + srcs: ["**/*.aidl"], +} + +aidl_interface { + name: "statsd-aidl", srcs: [ "android/os/IPendingIntentRef.aidl", "android/os/IPullAtomCallback.aidl", "android/os/IPullAtomResultReceiver.aidl", "android/os/IStatsCompanionService.aidl", "android/os/IStatsd.aidl", + "android/os/StatsDimensionsValueParcel.aidl", "android/util/StatsEventParcel.aidl", ], -} - -filegroup { - name: "statsd_java_aidl", - srcs: ["**/*.aidl"], -} - -// This library is currently unused -aidl_interface { - name: "stats-event-parcel-aidl", - srcs: ["android/util/StatsEventParcel.aidl"], backend: { java: { - sdk_version: "28", + enabled: false, // the platform uses statsd_java_aidl }, cpp: { - enabled: false, + enabled: true, + }, + ndk: { + enabled: true, } } } diff --git a/apex/statsd/aidl/android/os/IPendingIntentRef.aidl b/apex/statsd/aidl/android/os/IPendingIntentRef.aidl index 6b9e467a7e15..000a69992a49 100644 --- a/apex/statsd/aidl/android/os/IPendingIntentRef.aidl +++ b/apex/statsd/aidl/android/os/IPendingIntentRef.aidl @@ -16,7 +16,7 @@ package android.os; -import android.os.StatsDimensionsValue; +import android.os.StatsDimensionsValueParcel; /** * Binder interface to hold a PendingIntent for StatsCompanionService. @@ -42,5 +42,5 @@ interface IPendingIntentRef { */ oneway void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId, long subscriptionRuleId, in String[] cookies, - in StatsDimensionsValue dimensionsValue); -}
\ No newline at end of file + in StatsDimensionsValueParcel dimensionsValueParcel); +} diff --git a/apex/statsd/aidl/android/os/StatsDimensionsValueParcel.aidl b/apex/statsd/aidl/android/os/StatsDimensionsValueParcel.aidl new file mode 100644 index 000000000000..a8685e34dd52 --- /dev/null +++ b/apex/statsd/aidl/android/os/StatsDimensionsValueParcel.aidl @@ -0,0 +1,21 @@ +package android.os; + +/** + * @hide + */ +parcelable StatsDimensionsValueParcel { + /** + * Field equals: + * - atomTag for top level StatsDimensionsValueParcel + * - position in dimension for all other levels + */ + int field; + int valueType; + + String stringValue; + int intValue; + long longValue; + boolean boolValue; + float floatValue; + StatsDimensionsValueParcel[] tupleValue; +} diff --git a/apex/statsd/framework/java/android/os/StatsDimensionsValue.java b/apex/statsd/framework/java/android/os/StatsDimensionsValue.java index 886130fc5f14..71d43599fc82 100644 --- a/apex/statsd/framework/java/android/os/StatsDimensionsValue.java +++ b/apex/statsd/framework/java/android/os/StatsDimensionsValue.java @@ -96,6 +96,47 @@ public final class StatsDimensionsValue implements Parcelable { } /** + * Creates a {@code StatsDimensionsValue} from a StatsDimensionsValueParcel + * TODO(b/149103391): Make StatsDimensionsValue a wrapper on top of + * StatsDimensionsValueParcel. + * + * @hide + */ + public StatsDimensionsValue(StatsDimensionsValueParcel parcel) { + mField = parcel.field; + mValueType = parcel.valueType; + switch (mValueType) { + case STRING_VALUE_TYPE: + mValue = parcel.stringValue; + break; + case INT_VALUE_TYPE: + mValue = parcel.intValue; + break; + case LONG_VALUE_TYPE: + mValue = parcel.longValue; + break; + case BOOLEAN_VALUE_TYPE: + mValue = parcel.boolValue; + break; + case FLOAT_VALUE_TYPE: + mValue = parcel.floatValue; + break; + case TUPLE_VALUE_TYPE: + StatsDimensionsValue[] values = new StatsDimensionsValue[parcel.tupleValue.length]; + for (int i = 0; i < parcel.tupleValue.length; i++) { + values[i] = new StatsDimensionsValue(parcel.tupleValue[i]); + } + mValue = values; + break; + default: + Slog.w(TAG, "StatsDimensionsValueParcel contains bad valueType: " + mValueType); + mValue = null; + break; + } + } + + + /** * Return the field, i.e. the tag of a statsd atom. * * @return the field diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java index 4495dc9de71e..7cc6760f307b 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java @@ -24,6 +24,7 @@ import android.os.Binder; import android.os.IPendingIntentRef; import android.os.Process; import android.os.StatsDimensionsValue; +import android.os.StatsDimensionsValueParcel; import android.util.Slog; import com.android.server.SystemService; @@ -145,8 +146,10 @@ public class StatsCompanion { @Override public void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId, - long subscriptionRuleId, String[] cookies, StatsDimensionsValue dimensionsValue) { + long subscriptionRuleId, String[] cookies, + StatsDimensionsValueParcel dimensionsValueParcel) { enforceStatsdCallingUid(); + StatsDimensionsValue dimensionsValue = new StatsDimensionsValue(dimensionsValueParcel); Intent intent = new Intent() .putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid) diff --git a/apex/statsd/testing/Android.bp b/apex/statsd/testing/Android.bp index 22e73015ba39..a9cd0ccb53e8 100644 --- a/apex/statsd/testing/Android.bp +++ b/apex/statsd/testing/Android.bp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -apex { +apex_test { name: "test_com.android.os.statsd", visibility: [ "//system/apex/tests", diff --git a/api/current.txt b/api/current.txt index 294384055252..977dcde6a072 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4015,7 +4015,7 @@ package android.app { method public android.util.Size getAppTaskThumbnailSize(); method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks(); method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo(); - method @Nullable public java.util.List<android.app.ApplicationExitInfo> getHistoricalProcessExitReasons(@Nullable String, @IntRange(from=0) int, @IntRange(from=0) int); + method @NonNull public java.util.List<android.app.ApplicationExitInfo> getHistoricalProcessExitReasons(@Nullable String, @IntRange(from=0) int, @IntRange(from=0) int); method public int getLargeMemoryClass(); method public int getLauncherLargeIconDensity(); method public int getLauncherLargeIconSize(); @@ -4555,12 +4555,13 @@ package android.app { method public int getPackageUid(); method public int getPid(); method @NonNull public String getProcessName(); - method public int getPss(); + method public long getPss(); method public int getRealUid(); method public int getReason(); - method public int getRss(); + method public long getRss(); method public int getStatus(); method public long getTimestamp(); + method @NonNull public android.os.UserHandle getUserHandle(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.ApplicationExitInfo> CREATOR; field public static final int REASON_ANR = 6; // 0x6 @@ -30779,7 +30780,6 @@ package android.net.sip { method public void close(); method public void continueCall(int) throws android.net.sip.SipException; method public void endCall() throws android.net.sip.SipException; - method @Nullable public android.net.rtp.AudioGroup getAudioGroup(); method public android.net.sip.SipProfile getLocalProfile(); method public android.net.sip.SipProfile getPeerProfile(); method public int getState(); @@ -30790,7 +30790,6 @@ package android.net.sip { method public void makeCall(android.net.sip.SipProfile, android.net.sip.SipSession, int) throws android.net.sip.SipException; method public void sendDtmf(int); method public void sendDtmf(int, android.os.Message); - method public void setAudioGroup(@NonNull android.net.rtp.AudioGroup); method public void setListener(android.net.sip.SipAudioCall.Listener); method public void setListener(android.net.sip.SipAudioCall.Listener, boolean); method public void setSpeakerMode(boolean); @@ -30839,7 +30838,6 @@ package android.net.sip { method public void close(String) throws android.net.sip.SipException; method public android.net.sip.SipSession createSipSession(android.net.sip.SipProfile, android.net.sip.SipSession.Listener) throws android.net.sip.SipException; method public static String getCallId(android.content.Intent); - method @NonNull public java.util.List<android.net.sip.SipProfile> getListOfProfiles() throws android.net.sip.SipException; method public static String getOfferSessionDescription(android.content.Intent); method public android.net.sip.SipSession getSessionFor(android.content.Intent) throws android.net.sip.SipException; method public static boolean isApiSupported(android.content.Context); @@ -30857,11 +30855,6 @@ package android.net.sip { method public void setRegistrationListener(String, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; method public android.net.sip.SipAudioCall takeAudioCall(android.content.Intent, android.net.sip.SipAudioCall.Listener) throws android.net.sip.SipException; method public void unregister(android.net.sip.SipProfile, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; - field public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED"; - field public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL"; - field public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE"; - field public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP"; - field public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP"; field public static final String EXTRA_CALL_ID = "android:sipCallID"; field public static final String EXTRA_OFFER_SD = "android:sipOfferSD"; field public static final int INCOMING_CALL_RESULT_CODE = 101; // 0x65 @@ -30871,7 +30864,6 @@ package android.net.sip { method public int describeContents(); method public String getAuthUserName(); method public boolean getAutoRegistration(); - method public int getCallingUid(); method public String getDisplayName(); method public String getPassword(); method public int getPort(); @@ -37046,6 +37038,15 @@ package android.os { } +package android.os.ext.test { + + @Deprecated public class Test { + ctor @Deprecated public Test(); + method @Deprecated public void testE(); + } + +} + package android.os.health { public class HealthStats { @@ -43995,7 +43996,7 @@ package android.service.quicksettings { field public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE"; field public static final String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES"; field public static final String META_DATA_ACTIVE_TILE = "android.service.quicksettings.ACTIVE_TILE"; - field public static final String META_DATA_BOOLEAN_TILE = "android.service.quicksettings.BOOLEAN_TILE"; + field public static final String META_DATA_TOGGLEABLE_TILE = "android.service.quicksettings.TOGGLEABLE_TILE"; } } @@ -47312,7 +47313,7 @@ package android.telephony { method public void onSignalStrengthsChanged(android.telephony.SignalStrength); method public void onUserMobileDataStateChanged(boolean); field public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000 - field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000 + field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000 field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000 field public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8 field public static final int LISTEN_CALL_STATE = 32; // 0x20 @@ -47325,7 +47326,7 @@ package android.telephony { field public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4 field public static final int LISTEN_NONE = 0; // 0x0 field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000 - field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000 + field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000 field public static final int LISTEN_SERVICE_STATE = 1; // 0x1 field @Deprecated public static final int LISTEN_SIGNAL_STRENGTH = 2; // 0x2 field public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100 @@ -60889,7 +60890,7 @@ package android.widget { method public int getGravity(); method public float getHorizontalMargin(); method public float getVerticalMargin(); - method @Deprecated public android.view.View getView(); + method @Deprecated @Nullable public android.view.View getView(); method public int getXOffset(); method public int getYOffset(); method public static android.widget.Toast makeText(android.content.Context, CharSequence, int); diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index 8100b07c31e3..59aa145ce1e9 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -120,6 +120,14 @@ package android.net { } +package android.os.ext.test { + + @Deprecated public class Test { + method @Deprecated public void testD(); + } + +} + package android.util { public final class Log { diff --git a/api/system-current.txt b/api/system-current.txt index df7198aa2028..24936d5784f8 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -585,10 +585,6 @@ package android.app { field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR; } - public final class ApplicationExitInfo implements android.os.Parcelable { - method @NonNull public android.os.UserHandle getUserHandle(); - } - public class BroadcastOptions { method public static android.app.BroadcastOptions makeBasic(); method @RequiresPermission("android.permission.START_ACTIVITIES_FROM_BACKGROUND") public void setBackgroundActivityStartsAllowed(boolean); @@ -3866,6 +3862,20 @@ package android.location { method @NonNull public android.location.GnssReflectingPlane.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double); } + public final class GnssRequest implements android.os.Parcelable { + method public int describeContents(); + method public boolean isFullTracking(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssRequest> CREATOR; + } + + public static final class GnssRequest.Builder { + ctor public GnssRequest.Builder(); + ctor public GnssRequest.Builder(@NonNull android.location.GnssRequest); + method @NonNull public android.location.GnssRequest build(); + method @NonNull public android.location.GnssRequest.Builder setFullTracking(boolean); + } + public final class GnssSingleSatCorrection implements android.os.Parcelable { method public int describeContents(); method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz(); @@ -4139,6 +4149,7 @@ package android.location { method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler); + method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent); @@ -5746,7 +5757,6 @@ package android.media.tv.tuner.frontend { method public int getFreqOffset(); method public int getHierarchy(); method @NonNull public boolean[] getLayerErrors(); - method public int getLberCn(); method public int getLnbVoltage(); method public int getMer(); method public int getModulation(); @@ -5758,37 +5768,32 @@ package android.media.tv.tuner.frontend { method public int getSnr(); method public int getSpectralInversion(); method public int getSymbolRate(); - method public int getVberCn(); - method public int getXerCn(); method public boolean isDemodLocked(); method public boolean isEwbs(); method public boolean isLnaOn(); method public boolean isRfLock(); field public static final int FRONTEND_STATUS_TYPE_AGC = 14; // 0xe - field public static final int FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO = 24; // 0x18 + field public static final int FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO = 21; // 0x15 field public static final int FRONTEND_STATUS_TYPE_BER = 2; // 0x2 field public static final int FRONTEND_STATUS_TYPE_DEMOD_LOCK = 0; // 0x0 field public static final int FRONTEND_STATUS_TYPE_EWBS = 13; // 0xd field public static final int FRONTEND_STATUS_TYPE_FEC = 8; // 0x8 - field public static final int FRONTEND_STATUS_TYPE_FREQ_OFFSET = 21; // 0x15 - field public static final int FRONTEND_STATUS_TYPE_HIERARCHY = 22; // 0x16 + field public static final int FRONTEND_STATUS_TYPE_FREQ_OFFSET = 18; // 0x12 + field public static final int FRONTEND_STATUS_TYPE_HIERARCHY = 19; // 0x13 field public static final int FRONTEND_STATUS_TYPE_LAYER_ERROR = 16; // 0x10 - field public static final int FRONTEND_STATUS_TYPE_LBER_CN = 18; // 0x12 field public static final int FRONTEND_STATUS_TYPE_LNA = 15; // 0xf field public static final int FRONTEND_STATUS_TYPE_LNB_VOLTAGE = 11; // 0xb - field public static final int FRONTEND_STATUS_TYPE_MER = 20; // 0x14 + field public static final int FRONTEND_STATUS_TYPE_MER = 17; // 0x11 field public static final int FRONTEND_STATUS_TYPE_MODULATION = 9; // 0x9 field public static final int FRONTEND_STATUS_TYPE_PER = 3; // 0x3 field public static final int FRONTEND_STATUS_TYPE_PLP_ID = 12; // 0xc field public static final int FRONTEND_STATUS_TYPE_PRE_BER = 4; // 0x4 - field public static final int FRONTEND_STATUS_TYPE_RF_LOCK = 23; // 0x17 + field public static final int FRONTEND_STATUS_TYPE_RF_LOCK = 20; // 0x14 field public static final int FRONTEND_STATUS_TYPE_SIGNAL_QUALITY = 5; // 0x5 field public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH = 6; // 0x6 field public static final int FRONTEND_STATUS_TYPE_SNR = 1; // 0x1 field public static final int FRONTEND_STATUS_TYPE_SPECTRAL = 10; // 0xa field public static final int FRONTEND_STATUS_TYPE_SYMBOL_RATE = 7; // 0x7 - field public static final int FRONTEND_STATUS_TYPE_VBER_CN = 17; // 0x11 - field public static final int FRONTEND_STATUS_TYPE_XER_CN = 19; // 0x13 } public static class FrontendStatus.Atsc3PlpInfo { @@ -7210,6 +7215,28 @@ package android.net.netstats.provider { } +package android.net.sip { + + public class SipAudioCall { + method @Nullable public android.net.rtp.AudioGroup getAudioGroup(); + method public void setAudioGroup(@NonNull android.net.rtp.AudioGroup); + } + + public class SipManager { + method @NonNull public java.util.List<android.net.sip.SipProfile> getProfiles() throws android.net.sip.SipException; + field public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED"; + field public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL"; + field public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE"; + field public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP"; + field public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP"; + } + + public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable { + method public int getCallingUid(); + } + +} + package android.net.util { public final class SocketUtils { @@ -9146,6 +9173,15 @@ package android.os.ext { } +package android.os.ext.test { + + @Deprecated public class Test { + method @Deprecated public void testF(); + method @Deprecated public void testG(); + } + +} + package android.os.image { public class DynamicSystemClient { @@ -14131,6 +14167,10 @@ package android.view.contentcapture { method public boolean isContentCaptureFeatureEnabled(); } + public abstract class ContentCaptureSession implements java.lang.AutoCloseable { + field public static final int NO_SESSION_ID = 0; // 0x0 + } + public final class ViewNode extends android.app.assist.AssistStructure.ViewNode { method @Nullable public android.view.autofill.AutofillId getParentAutofillId(); } diff --git a/api/test-current.txt b/api/test-current.txt index e1f83822609d..e352cb65156e 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -923,6 +923,7 @@ package android.content.pm { field public static final int FLAG_PERMISSION_USER_SET = 1; // 0x1 field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000 field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000 + field public static final int MODULE_APEX_NAME = 1; // 0x1 field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services"; field public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared"; } @@ -2539,6 +2540,7 @@ package android.os { } public class UserManager { + method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.CREATE_USERS"}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle); method public static boolean isSplitSystemUser(); field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED"; } diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 7e069a6b4372..956fd29205cb 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -44,12 +44,8 @@ cc_library_host_shared { cc_defaults { name: "statsd_defaults", - aidl: { - include_dirs: ["frameworks/base/core/java"], - }, srcs: [ - ":statsd_aidl", "src/active_config_list.proto", "src/anomaly/AlarmMonitor.cpp", "src/anomaly/AlarmTracker.cpp", @@ -124,14 +120,14 @@ cc_defaults { "libstatslog", "libstatsmetadata", "libsysutils", + "libutils", ], shared_libs: [ "libbinder", "libincident", "liblog", - "libservices", "libstatssocket", - "libutils", + "statsd-aidl-cpp", ], } diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp index 5b75b97a0764..6b9d0e4fdac0 100644 --- a/cmds/statsd/src/HashableDimensionKey.cpp +++ b/cmds/statsd/src/HashableDimensionKey.cpp @@ -26,6 +26,86 @@ namespace statsd { using std::string; using std::vector; +// These constants must be kept in sync with those in StatsDimensionsValue.java +const static int STATS_DIMENSIONS_VALUE_STRING_TYPE = 2; +const static int STATS_DIMENSIONS_VALUE_INT_TYPE = 3; +const static int STATS_DIMENSIONS_VALUE_LONG_TYPE = 4; +// const static int STATS_DIMENSIONS_VALUE_BOOL_TYPE = 5; (commented out because +// unused -- statsd does not correctly support bool types) +const static int STATS_DIMENSIONS_VALUE_FLOAT_TYPE = 6; +const static int STATS_DIMENSIONS_VALUE_TUPLE_TYPE = 7; + +/** + * Recursive helper function that populates a parent StatsDimensionsValueParcel + * with children StatsDimensionsValueParcels. + * + * \param dims vector of FieldValues stored by HashableDimensionKey + * \param index positions in dims vector to start reading children from + * \param depth level of parent parcel in the full StatsDimensionsValueParcel + * tree + */ +static void populateStatsDimensionsValueParcelChildren(StatsDimensionsValueParcel &parentParcel, + const vector<FieldValue>& dims, size_t& index, + int depth, int prefix) { + while (index < dims.size()) { + const FieldValue& dim = dims[index]; + int fieldDepth = dim.mField.getDepth(); + int fieldPrefix = dim.mField.getPrefix(depth); + StatsDimensionsValueParcel childParcel; + childParcel.field = dim.mField.getPosAtDepth(depth); + if (depth > 2) { + ALOGE("Depth > 2 not supported by StatsDimensionsValueParcel."); + return; + } + if (depth == fieldDepth && prefix == fieldPrefix) { + switch (dim.mValue.getType()) { + case INT: + childParcel.valueType = STATS_DIMENSIONS_VALUE_INT_TYPE; + childParcel.intValue = dim.mValue.int_value; + break; + case LONG: + childParcel.valueType = STATS_DIMENSIONS_VALUE_LONG_TYPE; + childParcel.longValue = dim.mValue.long_value; + break; + case FLOAT: + childParcel.valueType = STATS_DIMENSIONS_VALUE_FLOAT_TYPE; + childParcel.floatValue = dim.mValue.float_value; + break; + case STRING: + childParcel.valueType = STATS_DIMENSIONS_VALUE_STRING_TYPE; + childParcel.stringValue = String16(dim.mValue.str_value.c_str()); + break; + default: + ALOGE("Encountered FieldValue with unsupported value type."); + break; + } + index++; + parentParcel.tupleValue.push_back(childParcel); + } else if (fieldDepth > depth && fieldPrefix == prefix) { + childParcel.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE; + populateStatsDimensionsValueParcelChildren(childParcel, dims, index, depth + 1, + dim.mField.getPrefix(depth + 1)); + parentParcel.tupleValue.push_back(childParcel); + } else { + return; + } + } +} + +StatsDimensionsValueParcel HashableDimensionKey::toStatsDimensionsValueParcel() const { + StatsDimensionsValueParcel parcel; + if (mValues.size() == 0) { + return parcel; + } + + parcel.field = mValues[0].mField.getTag(); + parcel.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE; + + size_t index = 0; + populateStatsDimensionsValueParcelChildren(parcel, mValues, index, /*depth=*/0, /*prefix=*/0); + return parcel; +} + android::hash_t hashDimension(const HashableDimensionKey& value) { android::hash_t hash = 0; for (const auto& fieldValue : value.getValues()) { diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h index 654e1358f2a1..4adcf967555e 100644 --- a/cmds/statsd/src/HashableDimensionKey.h +++ b/cmds/statsd/src/HashableDimensionKey.h @@ -16,10 +16,11 @@ #pragma once +#include <android/os/StatsDimensionsValueParcel.h> #include <utils/JenkinsHash.h> #include <vector> -#include "FieldValue.h" #include "android-base/stringprintf.h" +#include "FieldValue.h" #include "logd/LogEvent.h" namespace android { @@ -69,6 +70,8 @@ public: return nullptr; } + StatsDimensionsValueParcel toStatsDimensionsValueParcel() const; + std::string toString() const; bool operator!=(const HashableDimensionKey& that) const; diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp index 160b57e27c6c..8fd6b46d0716 100644 --- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp +++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp @@ -121,7 +121,7 @@ void SubscriberReporter::sendBroadcastLocked(const sp<IPendingIntentRef>& pir, subscription.id(), subscription.rule_id(), cookies, - getStatsDimensionsValue(dimKey.getDimensionKeyInWhat())); + dimKey.getDimensionKeyInWhat().toStatsDimensionsValueParcel()); } sp<IPendingIntentRef> SubscriberReporter::getBroadcastSubscriber(const ConfigKey& configKey, @@ -138,61 +138,6 @@ sp<IPendingIntentRef> SubscriberReporter::getBroadcastSubscriber(const ConfigKey return pirMapIt->second; } -void getStatsDimensionsValueHelper(const vector<FieldValue>& dims, size_t* index, int depth, - int prefix, vector<StatsDimensionsValue>* output) { - size_t count = dims.size(); - while (*index < count) { - const auto& dim = dims[*index]; - const int valueDepth = dim.mField.getDepth(); - const int valuePrefix = dim.mField.getPrefix(depth); - if (valueDepth > 2) { - ALOGE("Depth > 2 not supported"); - return; - } - if (depth == valueDepth && valuePrefix == prefix) { - switch (dim.mValue.getType()) { - case INT: - output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), - dim.mValue.int_value)); - break; - case LONG: - output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), - dim.mValue.long_value)); - break; - case FLOAT: - output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), - dim.mValue.float_value)); - break; - case STRING: - output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), - String16(dim.mValue.str_value.c_str()))); - break; - default: - break; - } - (*index)++; - } else if (valueDepth > depth && valuePrefix == prefix) { - vector<StatsDimensionsValue> childOutput; - getStatsDimensionsValueHelper(dims, index, depth + 1, dim.mField.getPrefix(depth + 1), - &childOutput); - output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), childOutput)); - } else { - return; - } - } -} - -StatsDimensionsValue SubscriberReporter::getStatsDimensionsValue(const HashableDimensionKey& dim) { - if (dim.getValues().size() == 0) { - return StatsDimensionsValue(); - } - - vector<StatsDimensionsValue> fields; - size_t index = 0; - getStatsDimensionsValueHelper(dim.getValues(), &index, 0, 0, &fields); - return StatsDimensionsValue(dim.getValues()[0].mField.getTag(), fields); -} - } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h index 087a1b84b91f..42599f508313 100644 --- a/cmds/statsd/src/subscriber/SubscriberReporter.h +++ b/cmds/statsd/src/subscriber/SubscriberReporter.h @@ -22,7 +22,6 @@ #include "config/ConfigKey.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // subscription -#include "android/os/StatsDimensionsValue.h" #include "HashableDimensionKey.h" #include <mutex> @@ -70,8 +69,6 @@ public: sp<IPendingIntentRef> getBroadcastSubscriber(const ConfigKey& configKey, int64_t subscriberId); - static StatsDimensionsValue getStatsDimensionsValue(const HashableDimensionKey& dim); - private: SubscriberReporter() {}; diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp index f4a59ed14d10..9e69d977f351 100644 --- a/cmds/statsd/tests/FieldValue_test.cpp +++ b/cmds/statsd/tests/FieldValue_test.cpp @@ -290,33 +290,34 @@ TEST(AtomMatcherTest, TestWriteDimensionPath) { } } -TEST(AtomMatcherTest, TestSubscriberDimensionWrite) { - HashableDimensionKey dim; - - int pos1[] = {1, 1, 1}; - int pos2[] = {1, 1, 2}; - int pos3[] = {1, 1, 3}; - int pos4[] = {2, 0, 0}; - - Field field1(10, pos1, 2); - Field field2(10, pos2, 2); - Field field3(10, pos3, 2); - Field field4(10, pos4, 0); - - Value value1((int32_t)10025); - Value value2("tag"); - Value value3((int32_t)987654); - Value value4((int32_t)99999); - - dim.addValue(FieldValue(field1, value1)); - dim.addValue(FieldValue(field2, value2)); - dim.addValue(FieldValue(field3, value3)); - dim.addValue(FieldValue(field4, value4)); - - SubscriberReporter::getStatsDimensionsValue(dim); - // TODO(b/110562792): can't test anything here because StatsDimensionsValue class doesn't - // have any read api. -} +//TODO(b/149050405) Update this test for StatsDimensionValueParcel +//TEST(AtomMatcherTest, TestSubscriberDimensionWrite) { +// HashableDimensionKey dim; +// +// int pos1[] = {1, 1, 1}; +// int pos2[] = {1, 1, 2}; +// int pos3[] = {1, 1, 3}; +// int pos4[] = {2, 0, 0}; +// +// Field field1(10, pos1, 2); +// Field field2(10, pos2, 2); +// Field field3(10, pos3, 2); +// Field field4(10, pos4, 0); +// +// Value value1((int32_t)10025); +// Value value2("tag"); +// Value value3((int32_t)987654); +// Value value4((int32_t)99999); +// +// dim.addValue(FieldValue(field1, value1)); +// dim.addValue(FieldValue(field2, value2)); +// dim.addValue(FieldValue(field3, value3)); +// dim.addValue(FieldValue(field4, value4)); +// +// SubscriberReporter::getStatsDimensionsValue(dim); +// // TODO(b/110562792): can't test anything here because StatsDimensionsValue class doesn't +// // have any read api. +//} TEST(AtomMatcherTest, TestWriteDimensionToProto) { HashableDimensionKey dim; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index db9aa18dbd5a..7ee44053d4d5 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -94,6 +94,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Locale; @@ -3555,13 +3556,13 @@ public class ActivityManager { * @return a list of {@link ApplicationExitInfo} records matching the criteria, sorted in * the order from most recent to least recent. */ - @Nullable + @NonNull public List<ApplicationExitInfo> getHistoricalProcessExitReasons(@Nullable String packageName, @IntRange(from = 0) int pid, @IntRange(from = 0) int maxNum) { try { ParceledListSlice<ApplicationExitInfo> r = getService().getHistoricalProcessExitReasons( packageName, pid, maxNum, mContext.getUserId()); - return r == null ? null : r.getList(); + return r == null ? Collections.emptyList() : r.getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java index 4bf5f07e86be..c55453e94960 100644 --- a/core/java/android/app/ApplicationExitInfo.java +++ b/core/java/android/app/ApplicationExitInfo.java @@ -19,7 +19,6 @@ package android.app; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SystemApi; import android.app.ActivityManager.RunningAppProcessInfo.Importance; import android.icu.text.SimpleDateFormat; import android.os.Parcel; @@ -245,12 +244,12 @@ public final class ApplicationExitInfo implements Parcelable { /** * @see {@link #getPss} */ - private int mPss; + private long mPss; /** * @see {@link #getRss} */ - private int mRss; + private long mRss; /** * @see {@link #getTimestamp} @@ -385,7 +384,7 @@ public final class ApplicationExitInfo implements Parcelable { * it's NOT the exact memory information prior to its death; and it'll be zero * if the process died before system had a chance to take the sample. </p> */ - public int getPss() { + public long getPss() { return mPss; } @@ -396,12 +395,13 @@ public final class ApplicationExitInfo implements Parcelable { * it's NOT the exact memory information prior to its death; and it'll be zero * if the process died before system had a chance to take the sample. </p> */ - public int getRss() { + public long getRss() { return mRss; } /** - * The timestamp of the process's death, in milliseconds since the epoch. + * The timestamp of the process's death, in milliseconds since the epoch, + * as returned by {@link System#currentTimeMillis System.currentTimeMillis()}. */ public long getTimestamp() { return mTimestamp; @@ -409,6 +409,9 @@ public final class ApplicationExitInfo implements Parcelable { /** * The human readable description of the process's death, given by the system; could be null. + * + * <p class="note">Note: only intended to be human-readable and the system provides no + * guarantees that the format is stable across devices or Android releases.</p> */ public @Nullable String getDescription() { return mDescription; @@ -416,10 +419,7 @@ public final class ApplicationExitInfo implements Parcelable { /** * Return the user id of the record on a multi-user system. - * - * @hide */ - @SystemApi public @NonNull UserHandle getUserHandle() { return UserHandle.of(UserHandle.getUserId(mRealUid)); } @@ -546,7 +546,7 @@ public final class ApplicationExitInfo implements Parcelable { * * @hide */ - public void setPss(final int pss) { + public void setPss(final long pss) { mPss = pss; } @@ -555,7 +555,7 @@ public final class ApplicationExitInfo implements Parcelable { * * @hide */ - public void setRss(final int rss) { + public void setRss(final long rss) { mRss = rss; } @@ -630,8 +630,8 @@ public final class ApplicationExitInfo implements Parcelable { dest.writeInt(mSubReason); dest.writeInt(mStatus); dest.writeInt(mImportance); - dest.writeInt(mPss); - dest.writeInt(mRss); + dest.writeLong(mPss); + dest.writeLong(mRss); dest.writeLong(mTimestamp); dest.writeString(mDescription); } @@ -669,8 +669,8 @@ public final class ApplicationExitInfo implements Parcelable { mSubReason = in.readInt(); mStatus = in.readInt(); mImportance = in.readInt(); - mPss = in.readInt(); - mRss = in.readInt(); + mPss = in.readLong(); + mRss = in.readLong(); mTimestamp = in.readLong(); mDescription = in.readString(); } @@ -848,10 +848,10 @@ public final class ApplicationExitInfo implements Parcelable { mImportance = proto.readInt(ApplicationExitInfoProto.IMPORTANCE); break; case (int) ApplicationExitInfoProto.PSS: - mPss = proto.readInt(ApplicationExitInfoProto.PSS); + mPss = proto.readLong(ApplicationExitInfoProto.PSS); break; case (int) ApplicationExitInfoProto.RSS: - mRss = proto.readInt(ApplicationExitInfoProto.RSS); + mRss = proto.readLong(ApplicationExitInfoProto.RSS); break; case (int) ApplicationExitInfoProto.TIMESTAMP: mTimestamp = proto.readLong(ApplicationExitInfoProto.TIMESTAMP); @@ -891,8 +891,8 @@ public final class ApplicationExitInfo implements Parcelable { result = 31 * result + mSubReason; result = 31 * result + mImportance; result = 31 * result + mStatus; - result = 31 * result + mPss; - result = 31 * result + mRss; + result = 31 * result + (int) mPss; + result = 31 * result + (int) mRss; result = 31 * result + Long.hashCode(mTimestamp); result = 31 * result + Objects.hashCode(mProcessName); result = 31 * result + Objects.hashCode(mDescription); diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 16c0910f1273..19397ed3ebaa 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -113,6 +113,7 @@ interface INotificationManager int getAppsBypassingDndCount(int uid); ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int userId); boolean isPackagePaused(String pkg); + void deleteNotificationHistoryItem(String pkg, int uid, long postedTime); void silenceNotificationSound(); diff --git a/core/java/android/app/ITaskOrganizerController.aidl b/core/java/android/app/ITaskOrganizerController.aidl index bfc42ef8848d..5d5956e4dca4 100644 --- a/core/java/android/app/ITaskOrganizerController.aidl +++ b/core/java/android/app/ITaskOrganizerController.aidl @@ -51,6 +51,9 @@ interface ITaskOrganizerController { /** Deletes a persistent root task in WM */ boolean deleteRootTask(IWindowContainer task); + /** Gets direct child tasks (ordered from top-to-bottom) */ + List<ActivityManager.RunningTaskInfo> getChildTasks(in IWindowContainer parent); + /** Get the root task which contains the current ime target */ IWindowContainer getImeTarget(int display); diff --git a/core/java/android/app/NotificationHistory.java b/core/java/android/app/NotificationHistory.java index 909a476f3c94..f26e62874347 100644 --- a/core/java/android/app/NotificationHistory.java +++ b/core/java/android/app/NotificationHistory.java @@ -346,6 +346,26 @@ public final class NotificationHistory implements Parcelable { } /** + * Removes an individual historical notification and regenerates the string pool + */ + public boolean removeNotificationFromWrite(String packageName, long postedTime) { + boolean removed = false; + for (int i = mNotificationsToWrite.size() - 1; i >= 0; i--) { + HistoricalNotification hn = mNotificationsToWrite.get(i); + if (packageName.equals(hn.getPackage()) + && postedTime == hn.getPostedTimeMs()) { + removed = true; + mNotificationsToWrite.remove(i); + } + } + if (removed) { + poolStringsFromNotifications(); + } + + return removed; + } + + /** * Gets pooled strings in order to write them to disk */ public @NonNull String[] getPooledStringsToWrite() { diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index f32a4ab43357..0e0161ff4e9f 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -700,6 +700,27 @@ public abstract class ContentResolver implements ContentInterface { /** @hide */ public static final String REMOTE_CALLBACK_RESULT = "result"; + /** + * How long we wait for an attached process to publish its content providers + * before we decide it must be hung. + * @hide + */ + public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS = 10 * 1000; + + /** + * How long we wait for an provider to be published. Should be longer than + * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS}. + * @hide + */ + public static final int CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS = + CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000; + + // Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how + // long ActivityManagerService is giving a content provider to get published if a new process + // needs to be started for that. + private static final int GET_TYPE_TIMEOUT_MILLIS = + CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS + 5 * 1000; + public ContentResolver(@Nullable Context context) { this(context, null); } @@ -849,8 +870,6 @@ public abstract class ContentResolver implements ContentInterface { } } - private static final int GET_TYPE_TIMEOUT_MILLIS = 3000; - private static class GetTypeResultListener implements RemoteCallback.OnResultListener { @GuardedBy("this") public boolean done; diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl index 04923590b413..38a9ac4a0d05 100644 --- a/core/java/android/content/pm/ILauncherApps.aidl +++ b/core/java/android/content/pm/ILauncherApps.aidl @@ -98,4 +98,9 @@ interface ILauncherApps { in ComponentName componentName, int flags, in IShortcutChangeCallback callback, int callbackId); void unregisterShortcutChangeCallback(String callingPackage, int callbackId); + + void cacheShortcuts(String callingPackage, String packageName, in List<String> shortcutIds, + in UserHandle user); + void uncacheShortcuts(String callingPackage, String packageName, in List<String> shortcutIds, + in UserHandle user); } diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 73c9e4d843b7..d2532783f47c 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -20,6 +20,7 @@ import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; @@ -1089,6 +1090,61 @@ public class LauncherApps { } /** + * Mark shortcuts as cached for a package. + * + * <p>Only dynamic long lived shortcuts can be cached. None dynamic or non long lived shortcuts + * in the list will be ignored. + * + * <p>Unlike pinned shortcuts, where different callers can have different sets of pinned + * shortcuts, cached state is per shortcut only, and even if multiple callers cache the same + * shortcut, it can be uncached by any valid caller. + * + * @param packageName The target package name. + * @param shortcutIds The IDs of the shortcut to be cached. + * @param user The UserHandle of the profile. + * @throws IllegalStateException when the user is locked, or when the {@code user} user + * is locked or not running. + * + * @see ShortcutManager + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS) + public void cacheShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds, + @NonNull UserHandle user) { + logErrorForInvalidProfileAccess(user); + try { + mService.cacheShortcuts(mContext.getPackageName(), packageName, shortcutIds, user); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Remove cached flag from shortcuts for a package. + * + * @param packageName The target package name. + * @param shortcutIds The IDs of the shortcut to be uncached. + * @param user The UserHandle of the profile. + * @throws IllegalStateException when the user is locked, or when the {@code user} user + * is locked or not running. + * + * @see ShortcutManager + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS) + public void uncacheShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds, + @NonNull UserHandle user) { + logErrorForInvalidProfileAccess(user); + try { + mService.uncacheShortcuts(mContext.getPackageName(), packageName, shortcutIds, user); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * @hide kept for testing. */ @Deprecated diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 9f7f4821a11e..e8668f1368fb 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -597,6 +597,7 @@ public abstract class PackageManager { * @hide */ @SystemApi + @TestApi public static final int MODULE_APEX_NAME = 0x00000001; /** @hide */ diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java index a11a1dd5a68b..a69905eb3de4 100644 --- a/core/java/android/content/pm/ShortcutServiceInternal.java +++ b/core/java/android/content/pm/ShortcutServiceInternal.java @@ -85,4 +85,11 @@ public abstract class ShortcutServiceInternal { public abstract boolean isForegroundDefaultLauncher(@NonNull String callingPackage, int callingUid); + + public abstract void cacheShortcuts(int launcherUserId, + @NonNull String callingPackage, @NonNull String packageName, + @NonNull List<String> shortcutIds, int userId); + public abstract void uncacheShortcuts(int launcherUserId, + @NonNull String callingPackage, @NonNull String packageName, + @NonNull List<String> shortcutIds, int userId); } diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java index 9bd39925f83f..c1df5b6d2e7e 100644 --- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java +++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java @@ -221,10 +221,8 @@ public class SoundTriggerModule { /** * Set a model specific {@link ModelParams} with the given value. This * parameter will keep its value for the duration the model is loaded regardless of starting - * and - * stopping recognition. Once the model is unloaded, the value will be lost. - * {@link SoundTriggerModule#queryParameter(int, int)} should be checked first before calling - * this method. + * and stopping recognition. Once the model is unloaded, the value will be lost. + * {@link #queryParameter} should be checked first before calling this method. * * @param soundModelHandle handle of model to apply parameter * @param modelParam {@link ModelParams} @@ -251,22 +249,14 @@ public class SoundTriggerModule { * for the duration the model is loaded regardless of starting and stopping recognition. * Once the model is unloaded, the value will be lost. If the value is not set, a default * value is returned. See {@link ModelParams} for parameter default values. - * {@link SoundTriggerModule#queryParameter(int, int)} should be checked first before + * {@link #queryParameter} should be checked first before * calling this method. Otherwise, an exception can be thrown. * * @param soundModelHandle handle of model to get parameter * @param modelParam {@link ModelParams} * @return value of parameter - * @throws UnsupportedOperationException if hal or model do not support this API. - * {@link SoundTriggerModule#queryParameter(int, int)} - * should - * be checked first. - * @throws IllegalArgumentException if invalid model handle or parameter is passed. - * {@link SoundTriggerModule#queryParameter(int, int)} - * should be checked first. */ - public synchronized int getParameter(int soundModelHandle, @ModelParams int modelParam) - throws UnsupportedOperationException, IllegalArgumentException { + public synchronized int getParameter(int soundModelHandle, @ModelParams int modelParam) { try { return mService.getModelParameter(soundModelHandle, ConversionUtil.api2aidlModelParameter(modelParam)); @@ -276,9 +266,8 @@ public class SoundTriggerModule { } /** - * Determine if parameter control is supported for the given model handle. - * This method should be checked prior to calling {@link SoundTriggerModule#setParameter} or - * {@link SoundTriggerModule#getParameter}. + * Query the parameter support and range for a given {@link ModelParams}. + * This method should be check prior to calling {@link #setParameter} or {@link #getParameter}. * * @param soundModelHandle handle of model to get parameter * @param modelParam {@link ModelParams} diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java index 26d9c7d687eb..75123528a6b8 100644 --- a/core/java/android/os/SharedMemory.java +++ b/core/java/android/os/SharedMemory.java @@ -27,6 +27,7 @@ import dalvik.system.VMRuntime; import java.io.Closeable; import java.io.FileDescriptor; +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.DirectByteBuffer; import java.nio.NioUtils; @@ -272,6 +273,20 @@ public final class SharedMemory implements Parcelable, Closeable { dest.writeFileDescriptor(mFileDescriptor); } + /** + * Returns a dup'd ParcelFileDescriptor from the SharedMemory FileDescriptor. + * This obeys standard POSIX semantics, where the + * new file descriptor shared state such as file position with the + * original file descriptor. + * TODO: propose this method as a public or system API for next release to achieve parity with + * NDK ASharedMemory_dupFromJava. + * + * @hide + */ + public ParcelFileDescriptor getFdDup() throws IOException { + return ParcelFileDescriptor.dup(mFileDescriptor); + } + public static final @android.annotation.NonNull Parcelable.Creator<SharedMemory> CREATOR = new Parcelable.Creator<SharedMemory>() { @Override diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index 25584f156084..3508b7031dd3 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -101,6 +101,8 @@ public final class Trace { public static final long TRACE_TAG_NNAPI = 1L << 25; /** @hide */ public static final long TRACE_TAG_RRO = 1L << 26; + /** @hide */ + public static final long TRACE_TAG_APEX_MANAGER = 1L << 18; private static final long TRACE_TAG_NOT_READY = 1L << 63; private static final int MAX_SECTION_NAME_LEN = 127; diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 6ed1d2c345f8..b202053b5d65 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -2325,10 +2325,12 @@ public class UserManager { * @param restrictionKey the string key representing the restriction * @param userHandle the UserHandle of the user for whom to retrieve the restrictions. */ + @TestApi @UnsupportedAppUsage - @RequiresPermission(Manifest.permission.MANAGE_USERS) - public boolean hasBaseUserRestriction(@UserRestrictionKey String restrictionKey, - UserHandle userHandle) { + @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, + Manifest.permission.CREATE_USERS}) + public boolean hasBaseUserRestriction(@UserRestrictionKey @NonNull String restrictionKey, + @NonNull UserHandle userHandle) { try { return mService.hasBaseUserRestriction(restrictionKey, userHandle.getIdentifier()); } catch (RemoteException re) { diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl index 21434a2aecba..9d98b3b7819b 100644 --- a/core/java/android/os/incremental/IIncrementalService.aidl +++ b/core/java/android/os/incremental/IIncrementalService.aidl @@ -103,4 +103,9 @@ interface IIncrementalService { * Deletes a storage given its ID. Deletes its bind mounts and unmount it. Stop its data loader. */ void deleteStorage(int storageId); + + /** + * Setting up native library directories and extract native libs onto a storage. + */ + boolean configureNativeBinaries(int storageId, in @utf8InCpp String apkFullPath, in @utf8InCpp String libDirRelativePath, in @utf8InCpp String abi); } diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java index 0024ac7a6b2e..ba38268949b5 100644 --- a/core/java/android/os/incremental/IncrementalManager.java +++ b/core/java/android/os/incremental/IncrementalManager.java @@ -229,16 +229,41 @@ public final class IncrementalManager { if (linkedApkStorage == null) { throw new IOException("Failed to create linked storage at dir: " + afterCodePathParent); } - linkedApkStorage.makeDirectory(afterCodePathName); - File[] files = beforeCodeFile.listFiles(); - for (int i = 0; i < files.length; i++) { - if (files[i].isFile()) { - String fileName = files[i].getName(); - apkStorage.makeLink( - fileName, linkedApkStorage, afterCodePathName + "/" + fileName); + linkFiles(apkStorage, beforeCodeFile, "", linkedApkStorage, afterCodePathName); + apkStorage.unBind(beforeCodePath); + } + + /** + * Recursively set up directories and link all the files from source storage to target storage. + * + * @param sourceStorage The storage that has all the files and directories underneath. + * @param sourceAbsolutePath The absolute path of the directory that holds all files and dirs. + * @param sourceRelativePath The relative path on the source directory, e.g., "" or "lib". + * @param targetStorage The target storage that will have the same files and directories. + * @param targetRelativePath The relative path to the directory on the target storage that + * should have all the files and dirs underneath, + * e.g., "packageName-random". + * @throws IOException When makeDirectory or makeLink fails on the Incremental File System. + */ + private void linkFiles(IncrementalStorage sourceStorage, File sourceAbsolutePath, + String sourceRelativePath, IncrementalStorage targetStorage, + String targetRelativePath) throws IOException { + targetStorage.makeDirectory(targetRelativePath); + final File[] entryList = sourceAbsolutePath.listFiles(); + for (int i = 0; i < entryList.length; i++) { + final File entry = entryList[i]; + final String entryName = entryList[i].getName(); + final String sourceEntryRelativePath = + sourceRelativePath.isEmpty() ? entryName : sourceRelativePath + "/" + entryName; + final String targetEntryRelativePath = targetRelativePath + "/" + entryName; + if (entry.isFile()) { + sourceStorage.makeLink( + sourceEntryRelativePath, targetStorage, targetEntryRelativePath); + } else if (entry.isDirectory()) { + linkFiles(sourceStorage, entry, sourceEntryRelativePath, targetStorage, + targetEntryRelativePath); } } - apkStorage.unBind(beforeCodePath); } /** diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java index c4b843b6ce33..5df44ff49059 100644 --- a/core/java/android/os/incremental/IncrementalStorage.java +++ b/core/java/android/os/incremental/IncrementalStorage.java @@ -416,4 +416,24 @@ public final class IncrementalStorage { return false; } } + + /** + * Configure all the lib files inside Incremental Service, e.g., create lib dirs, create new lib + * files, extract original lib file data from zip and then write data to the lib files on the + * Incremental File System. + * + * @param apkFullPath Source APK to extract native libs from. + * @param libDirRelativePath Target dir to put lib files, e.g., "lib" or "lib/arm". + * @param abi Target ABI of the native lib files. Only extract native libs of this ABI. + * @return Success of not. + */ + public boolean configureNativeBinaries(String apkFullPath, String libDirRelativePath, + String abi) { + try { + return mService.configureNativeBinaries(mId, apkFullPath, libDirRelativePath, abi); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + return false; + } + } } diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index 707426a22889..0edd01330fdd 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -345,9 +345,11 @@ public abstract class ContentCaptureService extends Service { } /** - * Notifies the service of {@link SnapshotData snapshot data} associated with a session. + * Notifies the service of {@link SnapshotData snapshot data} associated with an activity. * - * @param sessionId the session's Id + * @param sessionId the session's Id. This may also be + * {@link ContentCaptureSession#NO_SESSION_ID} if no content capture session + * exists for the activity being snapshotted * @param snapshotData the data */ public void onActivitySnapshot(@NonNull ContentCaptureSessionId sessionId, diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java index d0675ed4b99a..b4b5819c7d5f 100644 --- a/core/java/android/service/quicksettings/TileService.java +++ b/core/java/android/service/quicksettings/TileService.java @@ -126,22 +126,22 @@ public class TileService extends Service { = "android.service.quicksettings.ACTIVE_TILE"; /** - * Meta-data for a tile to support {@code BooleanState}. + * Meta-data for a tile to mark is toggleable. * <p> - * BooleanState is for tiles that should support switch tile behavior in accessibility. This is + * Toggleable tiles support switch tile behavior in accessibility. This is * the behavior of most of the framework tiles. * - * To make a TileService support BooleanState, set this meta-data to true on the TileService's - * manifest declaration. + * To indicate that a TileService is toggleable, set this meta-data to true on the + * TileService's manifest declaration. * <pre class="prettyprint"> * {@literal - * <meta-data android:name="android.service.quicksettings.BOOLEAN_TILE" + * <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE" * android:value="true" /> * } * </pre> */ - public static final String META_DATA_BOOLEAN_TILE = - "android.service.quicksettings.BOOLEAN_TILE"; + public static final String META_DATA_TOGGLEABLE_TILE = + "android.service.quicksettings.TOGGLEABLE_TILE"; /** * Used to notify SysUI that Listening has be requested. diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index 531ade04fe02..e65bd9f20ec4 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -412,23 +412,23 @@ public class PhoneStateListener { * domain. This indication does not necessarily indicate a change of service state, which should * be tracked via {@link #LISTEN_SERVICE_STATE}. * - * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling - * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or + * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). * * @see #onRegistrationFailed() */ - @RequiresPermission(Manifest.permission.READ_PHONE_STATE) + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 0x40000000; /** * Listen for Barring Information for the current registered / camped cell. * - * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling - * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). + * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or + * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). * * @see #onBarringInfoChanged() */ - @RequiresPermission(Manifest.permission.READ_PHONE_STATE) + @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = 0x80000000; /* diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index a407bd8f001e..a6f8fad817e1 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -12729,12 +12729,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return findViewInsideOutShouldExist(root, mNextFocusForwardId); case FOCUS_BACKWARD: { if (mID == View.NO_ID) return null; - return root.findViewByPredicateInsideOut(this, new Predicate<View>() { - @Override - public boolean test(View t) { - return t.findViewById(t.mNextFocusForwardId) == View.this; - } - }); + final View rootView = root; + final View startView = this; + // Since we have forward links but no backward links, we need to find the view that + // forward links to this view. We can't just find the view with the specified ID + // because view IDs need not be unique throughout the tree. + return root.findViewByPredicateInsideOut(startView, + t -> findViewInsideOutShouldExist(rootView, t, t.mNextFocusForwardId) + == startView); } } return null; @@ -12764,11 +12766,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } private View findViewInsideOutShouldExist(View root, int id) { + return findViewInsideOutShouldExist(root, this, id); + } + + private View findViewInsideOutShouldExist(View root, View start, int id) { if (mMatchIdPredicate == null) { mMatchIdPredicate = new MatchIdPredicate(); } mMatchIdPredicate.mId = id; - View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); + View result = root.findViewByPredicateInsideOut(start, mMatchIdPredicate); if (result == null) { Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); } diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java index 33f21f211a1a..cf34b0bad78d 100644 --- a/core/java/android/view/WindowContainerTransaction.java +++ b/core/java/android/view/WindowContainerTransaction.java @@ -16,6 +16,8 @@ package android.view; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.WindowConfiguration; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -25,6 +27,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** @@ -36,10 +40,14 @@ import java.util.Map; public class WindowContainerTransaction implements Parcelable { private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>(); + // Flat list because re-order operations are order-dependent + private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>(); + public WindowContainerTransaction() {} protected WindowContainerTransaction(Parcel in) { in.readMap(mChanges, null /* loader */); + in.readList(mHierarchyOps, null /* loader */); } private Change getOrCreateChange(IBinder token) { @@ -97,10 +105,39 @@ public class WindowContainerTransaction implements Parcelable { return this; } + /** + * Reparents a container into another one. The effect of a {@code null} parent can vary. For + * example, reparenting a stack to {@code null} will reparent it to its display. + * + * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to + * the bottom. + */ + public WindowContainerTransaction reparent(@NonNull IWindowContainer child, + @Nullable IWindowContainer parent, boolean onTop) { + mHierarchyOps.add(new HierarchyOp(child.asBinder(), + parent == null ? null : parent.asBinder(), onTop)); + return this; + } + + /** + * Reorders a container within its parent. + * + * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to + * the bottom. + */ + public WindowContainerTransaction reorder(@NonNull IWindowContainer child, boolean onTop) { + mHierarchyOps.add(new HierarchyOp(child.asBinder(), onTop)); + return this; + } + public Map<IBinder, Change> getChanges() { return mChanges; } + public List<HierarchyOp> getHierarchyOps() { + return mHierarchyOps; + } + @Override public String toString() { return "WindowContainerTransaction { changes = " + mChanges + " }"; @@ -109,6 +146,7 @@ public class WindowContainerTransaction implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeMap(mChanges); + dest.writeList(mHierarchyOps); } @Override @@ -249,4 +287,88 @@ public class WindowContainerTransaction implements Parcelable { } }; } + + /** + * Holds information about a reparent/reorder operation in the hierarchy. This is separate from + * Changes because they must be executed in the same order that they are added. + */ + public static class HierarchyOp implements Parcelable { + private final IBinder mContainer; + + // If this is same as mContainer, then only change position, don't reparent. + private final IBinder mReparent; + + // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom. + private final boolean mToTop; + + public HierarchyOp(@NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) { + mContainer = container; + mReparent = reparent; + mToTop = toTop; + } + + public HierarchyOp(@NonNull IBinder container, boolean toTop) { + mContainer = container; + mReparent = container; + mToTop = toTop; + } + + protected HierarchyOp(Parcel in) { + mContainer = in.readStrongBinder(); + mReparent = in.readStrongBinder(); + mToTop = in.readBoolean(); + } + + public boolean isReparent() { + return mContainer != mReparent; + } + + @Nullable + public IBinder getNewParent() { + return mReparent; + } + + @NonNull + public IBinder getContainer() { + return mContainer; + } + + public boolean getToTop() { + return mToTop; + } + + @Override + public String toString() { + if (isReparent()) { + return "{reparent: " + mContainer + " to " + (mToTop ? "top of " : "bottom of ") + + mReparent + "}"; + } else { + return "{reorder: " + mContainer + " to " + (mToTop ? "top" : "bottom") + "}"; + } + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeStrongBinder(mContainer); + dest.writeStrongBinder(mReparent); + dest.writeBoolean(mToTop); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator<HierarchyOp> CREATOR = new Creator<HierarchyOp>() { + @Override + public HierarchyOp createFromParcel(Parcel in) { + return new HierarchyOp(in); + } + + @Override + public HierarchyOp[] newArray(int size) { + return new HierarchyOp[size]; + } + }; + } } diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 232d96ba7f43..2134dab7986b 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -22,6 +22,7 @@ import android.annotation.CallSuper; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.util.DebugUtils; import android.util.Log; import android.view.View; @@ -50,7 +51,11 @@ public abstract class ContentCaptureSession implements AutoCloseable { private static final Random sIdGenerator = new Random(); - /** @hide */ + /** + * ID used to indicate that a session does not exist + * @hide + */ + @SystemApi public static final int NO_SESSION_ID = 0; /** diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index f0c16aadf12f..dbab81b129a9 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -664,8 +664,6 @@ public final class InputMethodManager { */ @Override public void setCurrentRootView(ViewRootImpl rootView) { - // If the mCurRootView is losing window focus, release the strong reference to it - // so as not to prevent it from being garbage-collected. if (mWindowFocusGainFuture != null) { mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */); mWindowFocusGainFuture = null; diff --git a/core/java/android/webkit/WebResourceRequest.java b/core/java/android/webkit/WebResourceRequest.java index 964b6f8e259d..0b307e63ca45 100644 --- a/core/java/android/webkit/WebResourceRequest.java +++ b/core/java/android/webkit/WebResourceRequest.java @@ -32,10 +32,10 @@ public interface WebResourceRequest { Uri getUrl(); /** - * Gets whether the request was made for the main frame. + * Gets whether the request was made in order to fetch the main frame's document. * - * @return whether the request was made for the main frame. Will be {@code false} for iframes, - * for example. + * @return whether the request was made for the main frame document. Will be + * {@code false} for subresources or iframes, for example. */ boolean isForMainFrame(); diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index a2c70b9afbee..8c52d1fadc52 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -263,9 +263,14 @@ public class Toast { /** * Return the view. * - * <p><strong>Warning:</strong> Starting from Android {@link Build.VERSION_CODES#R}, for apps - * targeting API level {@link Build.VERSION_CODES#R} or higher that haven't called {@link - * #setView(View)} with a non-{@code null} view, this method will return {@code null}. + * <p>Toasts constructed with {@link #Toast(Context)} that haven't called {@link #setView(View)} + * with a non-{@code null} view will return {@code null} here. + * + * <p>Starting from Android {@link Build.VERSION_CODES#R}, in apps targeting API level {@link + * Build.VERSION_CODES#R} or higher, toasts constructed with {@link #makeText(Context, + * CharSequence, int)} or its variants will also return {@code null} here unless they had called + * {@link #setView(View)} with a non-{@code null} view. If you want to be notified when the + * toast is shown or hidden, use {@link #addCallback(Callback)}. * * @see #setView * @deprecated Custom toast views are deprecated. Apps can create a standard text toast with the @@ -276,7 +281,7 @@ public class Toast { * will not have custom toast views displayed. */ @Deprecated - public View getView() { + @Nullable public View getView() { return mNextView; } diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index bbb751359bab..a934de328989 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -1487,7 +1487,6 @@ public class ResolverActivity extends Activity implements for (int i = 0; i < tabWidget.getChildCount(); i++) { TextView title = tabWidget.getChildAt(i).findViewById(android.R.id.title); title.setTextColor(getColor(R.color.resolver_tabs_inactive_color)); - title.setAllCaps(false); } } diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 22fe31eeda38..0ccc45e000e6 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -25,6 +25,7 @@ import static android.system.OsConstants.S_IRWXU; import static android.system.OsConstants.S_IXGRP; import static android.system.OsConstants.S_IXOTH; +import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; @@ -32,7 +33,12 @@ import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.parsing.AndroidPackage; import android.os.Build; +import android.os.IBinder; import android.os.SELinux; +import android.os.ServiceManager; +import android.os.incremental.IIncrementalService; +import android.os.incremental.IncrementalManager; +import android.os.incremental.IncrementalStorage; import android.system.ErrnoException; import android.system.Os; import android.util.Slog; @@ -44,6 +50,7 @@ import java.io.Closeable; import java.io.File; import java.io.FileDescriptor; import java.io.IOException; +import java.nio.file.Path; import java.util.List; /** @@ -73,6 +80,7 @@ public class NativeLibraryHelper { private final CloseGuard mGuard = CloseGuard.get(); private volatile boolean mClosed; + final String[] apkPaths; final long[] apkHandles; final boolean multiArch; final boolean extractNativeLibs; @@ -103,9 +111,11 @@ public class NativeLibraryHelper { private static Handle create(List<String> codePaths, boolean multiArch, boolean extractNativeLibs, boolean debuggable) throws IOException { final int size = codePaths.size(); + final String[] apkPaths = new String[size]; final long[] apkHandles = new long[size]; for (int i = 0; i < size; i++) { final String path = codePaths.get(i); + apkPaths[i] = path; apkHandles[i] = nativeOpenApk(path); if (apkHandles[i] == 0) { // Unwind everything we've opened so far @@ -116,7 +126,7 @@ public class NativeLibraryHelper { } } - return new Handle(apkHandles, multiArch, extractNativeLibs, debuggable); + return new Handle(apkPaths, apkHandles, multiArch, extractNativeLibs, debuggable); } public static Handle createFd(PackageLite lite, FileDescriptor fd) throws IOException { @@ -127,11 +137,13 @@ public class NativeLibraryHelper { throw new IOException("Unable to open APK " + path + " from fd " + fd); } - return new Handle(apkHandles, lite.multiArch, lite.extractNativeLibs, lite.debuggable); + return new Handle(new String[]{path}, apkHandles, lite.multiArch, + lite.extractNativeLibs, lite.debuggable); } - Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs, - boolean debuggable) { + Handle(String[] apkPaths, long[] apkHandles, boolean multiArch, + boolean extractNativeLibs, boolean debuggable) { + this.apkPaths = apkPaths; this.apkHandles = apkHandles; this.multiArch = multiArch; this.extractNativeLibs = extractNativeLibs; @@ -313,40 +325,58 @@ public class NativeLibraryHelper { } public static int copyNativeBinariesForSupportedAbi(Handle handle, File libraryRoot, - String[] abiList, boolean useIsaSubdir) throws IOException { - createNativeLibrarySubdir(libraryRoot); - + String[] abiList, boolean useIsaSubdir, boolean isIncremental) throws IOException { /* * If this is an internal application or our nativeLibraryPath points to * the app-lib directory, unpack the libraries if necessary. */ int abi = findSupportedAbi(handle, abiList); - if (abi >= 0) { - /* - * If we have a matching instruction set, construct a subdir under the native - * library root that corresponds to this instruction set. - */ - final String instructionSet = VMRuntime.getInstructionSet(abiList[abi]); - final File subDir; - if (useIsaSubdir) { - final File isaSubdir = new File(libraryRoot, instructionSet); - createNativeLibrarySubdir(isaSubdir); - subDir = isaSubdir; - } else { - subDir = libraryRoot; - } + if (abi < 0) { + return abi; + } - int copyRet = copyNativeBinaries(handle, subDir, abiList[abi]); - if (copyRet != PackageManager.INSTALL_SUCCEEDED) { - return copyRet; + /* + * If we have a matching instruction set, construct a subdir under the native + * library root that corresponds to this instruction set. + */ + final String supportedAbi = abiList[abi]; + final String instructionSet = VMRuntime.getInstructionSet(supportedAbi); + final File subDir; + if (useIsaSubdir) { + subDir = new File(libraryRoot, instructionSet); + } else { + subDir = libraryRoot; + } + + if (isIncremental) { + int res = + incrementalConfigureNativeBinariesForSupportedAbi(handle, subDir, supportedAbi); + if (res != PackageManager.INSTALL_SUCCEEDED) { + // TODO(b/133435829): the caller of this function expects that we return the index + // to the supported ABI. However, any non-negative integer can be a valid index. + // We should fix this function and make sure it doesn't accidentally return an error + // code that can also be a valid index. + return res; } + return abi; + } + + // For non-incremental, use regular extraction and copy + createNativeLibrarySubdir(libraryRoot); + if (subDir != libraryRoot) { + createNativeLibrarySubdir(subDir); + } + + int copyRet = copyNativeBinaries(handle, subDir, supportedAbi); + if (copyRet != PackageManager.INSTALL_SUCCEEDED) { + return copyRet; } return abi; } public static int copyNativeBinariesWithOverride(Handle handle, File libraryRoot, - String abiOverride) { + String abiOverride, boolean isIncremental) { try { if (handle.multiArch) { // Warn if we've set an abiOverride for multi-lib packages.. @@ -359,7 +389,8 @@ public class NativeLibraryHelper { int copyRet = PackageManager.NO_NATIVE_LIBRARIES; if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, - Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */); + Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */, + isIncremental); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { Slog.w(TAG, "Failure copying 32 bit native libraries; copyRet=" +copyRet); @@ -369,7 +400,8 @@ public class NativeLibraryHelper { if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, - Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */); + Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */, + isIncremental); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) { Slog.w(TAG, "Failure copying 64 bit native libraries; copyRet=" +copyRet); @@ -392,7 +424,7 @@ public class NativeLibraryHelper { } int copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, abiList, - true /* use isa specific subdirs */); + true /* use isa specific subdirs */, isIncremental); if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { Slog.w(TAG, "Failure copying native libraries [errorCode=" + copyRet + "]"); return copyRet; @@ -449,29 +481,61 @@ public class NativeLibraryHelper { * Service will create native library directories and set up native library binary files in the * same structure as they are in non-incremental installations. * - * @param pkg The package to be installed, including all the APK files. - * @param handle The pointer to an zip archive. - * @param libraryRoot The root directory of the native library files, e.g., lib/ - * @param abiList The list of ABIs that are supported by the current device. - * @param useIsaSubdir Whether or not to set up a sub dir for the ISA. - * @return ABI code if installation succeeds or error code if installation fails. + * @param handle The Handle object that contains all apk paths. + * @param libSubDir The target directory to put the native library files, e.g., lib/ or lib/arm + * @param abi The abi that is supported by the current device. + * @return Integer code if installation succeeds or fails. */ - public static int configureNativeBinariesForSupportedAbi(AndroidPackage pkg, Handle handle, - File libraryRoot, String[] abiList, boolean useIsaSubdir) { - int abi = findSupportedAbi(handle, abiList); - if (abi < 0) { - Slog.e(TAG, "Failed to find find matching ABI."); - return abi; + private static int incrementalConfigureNativeBinariesForSupportedAbi(Handle handle, + File libSubDir, String abi) { + final String[] apkPaths = handle.apkPaths; + if (apkPaths == null || apkPaths.length == 0) { + Slog.e(TAG, "No apks to extract native libraries from."); + return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } - // Currently only support installations that have pre-configured native library files - // TODO(b/136132412): implement this after incfs supports file mapping - if (!libraryRoot.exists()) { - Slog.e(TAG, "Incremental installation currently does not configure native libs"); - return INSTALL_FAILED_NO_MATCHING_ABIS; + final IBinder incrementalService = ServiceManager.getService(Context.INCREMENTAL_SERVICE); + if (incrementalService == null) { + //TODO(b/133435829): add incremental specific error codes + return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; + } + final IncrementalManager incrementalManager = new IncrementalManager( + IIncrementalService.Stub.asInterface(incrementalService)); + final File apkParent = new File(apkPaths[0]).getParentFile(); + IncrementalStorage incrementalStorage = + incrementalManager.openStorage(apkParent.getAbsolutePath()); + if (incrementalStorage == null) { + Slog.e(TAG, "Failed to find incremental storage"); + return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } - return abi; + String libRelativeDir = getRelativePath(apkParent, libSubDir); + if (libRelativeDir == null) { + return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; + } + + for (int i = 0; i < apkPaths.length; i++) { + if (!incrementalStorage.configureNativeBinaries(apkPaths[i], libRelativeDir, abi)) { + return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; + } + } + return PackageManager.INSTALL_SUCCEEDED; + } + + private static String getRelativePath(File base, File target) { + try { + final Path basePath = base.toPath(); + final Path targetPath = target.toPath(); + final Path relativePath = basePath.relativize(targetPath); + if (relativePath.toString().isEmpty()) { + return ""; + } + return relativePath.toString(); + } catch (IllegalArgumentException ex) { + Slog.e(TAG, "Failed to find relative path between: " + base.getAbsolutePath() + + " and: " + target.getAbsolutePath()); + return null; + } } // We don't care about the other return values for now. diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 26d2f19b13b6..2fcc1de776fb 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -903,7 +903,6 @@ public class SystemConfig { } break; case "component-override": { readComponentOverrides(parser, permFile); - XmlUtils.skipCurrentTag(parser); } break; case "backup-transport-whitelisted-service": { if (allowFeatures) { @@ -1403,8 +1402,7 @@ public class SystemConfig { final int depth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, depth)) { - String name = parser.getName(); - if ("component".equals(name)) { + if ("component".equals(parser.getName())) { String clsname = parser.getAttributeValue(null, "class"); String enabled = parser.getAttributeValue(null, "enabled"); if (clsname == null) { @@ -1432,8 +1430,6 @@ public class SystemConfig { } componentEnabledStates.put(clsname, !"false".equals(enabled)); - } else { - XmlUtils.skipCurrentTag(parser); } } } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 3d0926d61789..76e7e191d293 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -182,6 +182,7 @@ cc_library_shared { "android_hardware_UsbRequest.cpp", "android_hardware_location_ActivityRecognitionHardware.cpp", "android_util_FileObserver.cpp", + "android/graphics/GraphicsStatsService.cpp", "android/graphics/SurfaceTexture.cpp", "android/opengl/poly_clip.cpp", // TODO: .arm "android/opengl/util.cpp", @@ -273,6 +274,7 @@ cc_library_shared { "libstats_jni", "libstatslog", "server_configurable_flags", + "libstatspull", ], export_shared_lib_headers: [ // AndroidRuntime.h depends on nativehelper/jni.h diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp index 8fc6afa0f386..2a56fd6d6d17 100644 --- a/core/jni/android/graphics/FontFamily.cpp +++ b/core/jni/android/graphics/FontFamily.cpp @@ -34,9 +34,9 @@ #include <hwui/MinikinSkia.h> #include <hwui/Typeface.h> -#include <utils/FatVector.h> #include <minikin/FontFamily.h> #include <minikin/LocaleList.h> +#include <ui/FatVector.h> #include <memory> @@ -109,7 +109,7 @@ static jlong FontFamily_getFamilyReleaseFunc(CRITICAL_JNI_PARAMS) { static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex, jint weight, jint italic) { - uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes; + FatVector<SkFontArguments::Axis, 2> skiaAxes; for (const auto& axis : builder->axes) { skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value}); } diff --git a/core/jni/android/graphics/GraphicsStatsService.cpp b/core/jni/android/graphics/GraphicsStatsService.cpp new file mode 100644 index 000000000000..ef0aacc4d9ec --- /dev/null +++ b/core/jni/android/graphics/GraphicsStatsService.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "GraphicsStatsService" + +#include <JankTracker.h> +#include <jni.h> +#include <log/log.h> +#include <nativehelper/JNIHelp.h> +#include <nativehelper/ScopedPrimitiveArray.h> +#include <nativehelper/ScopedUtfChars.h> +#include <service/GraphicsStatsService.h> +#include <stats_event.h> +#include <stats_pull_atom_callback.h> +#include <statslog.h> +#include "core_jni_helpers.h" + +namespace android { + +using namespace android::uirenderer; + +static jint getAshmemSize(JNIEnv*, jobject) { + return sizeof(ProfileData); +} + +static jlong createDump(JNIEnv*, jobject, jint fd, jboolean isProto) { + GraphicsStatsService::Dump* dump = + GraphicsStatsService::createDump(fd, + isProto ? GraphicsStatsService::DumpType::Protobuf + : GraphicsStatsService::DumpType::Text); + return reinterpret_cast<jlong>(dump); +} + +static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage, + jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) { + std::string path; + const ProfileData* data = nullptr; + LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null"); + ScopedByteArrayRO buffer{env}; + if (jdata != nullptr) { + buffer.reset(jdata); + LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData), + "Buffer size %zu doesn't match expected %zu!", buffer.size(), + sizeof(ProfileData)); + data = reinterpret_cast<const ProfileData*>(buffer.get()); + } + if (jpath != nullptr) { + ScopedUtfChars pathChars(env, jpath); + LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), + "Failed to get path chars"); + path.assign(pathChars.c_str(), pathChars.size()); + } + ScopedUtfChars packageChars(env, jpackage); + LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(), + "Failed to get path chars"); + GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr); + LOG_ALWAYS_FATAL_IF(!dump, "null passed for dump pointer"); + + const std::string package(packageChars.c_str(), packageChars.size()); + GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime, data); +} + +static void addFileToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath) { + ScopedUtfChars pathChars(env, jpath); + LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars"); + const std::string path(pathChars.c_str(), pathChars.size()); + GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr); + GraphicsStatsService::addToDump(dump, path); +} + +static void finishDump(JNIEnv*, jobject, jlong dumpPtr) { + GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr); + GraphicsStatsService::finishDump(dump); +} + +static void finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr, jlong pulledData, + jboolean lastFullDay) { + GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr); + AStatsEventList* data = reinterpret_cast<AStatsEventList*>(pulledData); + GraphicsStatsService::finishDumpInMemory(dump, data, lastFullDay == JNI_TRUE); +} + +static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpackage, + jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) { + ScopedByteArrayRO buffer(env, jdata); + LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData), + "Buffer size %zu doesn't match expected %zu!", buffer.size(), + sizeof(ProfileData)); + ScopedUtfChars pathChars(env, jpath); + LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars"); + ScopedUtfChars packageChars(env, jpackage); + LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(), + "Failed to get path chars"); + + const std::string path(pathChars.c_str(), pathChars.size()); + const std::string package(packageChars.c_str(), packageChars.size()); + const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer.get()); + GraphicsStatsService::saveBuffer(path, package, versionCode, startTime, endTime, data); +} + +static jobject gGraphicsStatsServiceObject = nullptr; +static jmethodID gGraphicsStatsService_pullGraphicsStatsMethodID; + +static JNIEnv* getJNIEnv() { + JavaVM* vm = AndroidRuntime::getJavaVM(); + JNIEnv* env = nullptr; + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) { + LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!"); + } + } + return env; +} + +// graphicsStatsPullCallback is invoked by statsd service to pull GRAPHICS_STATS atom. +static AStatsManager_PullAtomCallbackReturn graphicsStatsPullCallback(int32_t atom_tag, + AStatsEventList* data, + void* cookie) { + JNIEnv* env = getJNIEnv(); + if (!env) { + return false; + } + if (gGraphicsStatsServiceObject == nullptr) { + ALOGE("Failed to get graphicsstats service"); + return AStatsManager_PULL_SKIP; + } + + for (bool lastFullDay : {true, false}) { + env->CallVoidMethod(gGraphicsStatsServiceObject, + gGraphicsStatsService_pullGraphicsStatsMethodID, + (jboolean)(lastFullDay ? JNI_TRUE : JNI_FALSE), + reinterpret_cast<jlong>(data)); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + ALOGE("Failed to invoke graphicsstats service"); + return AStatsManager_PULL_SKIP; + } + } + return AStatsManager_PULL_SUCCESS; +} + +// Register a puller for GRAPHICS_STATS atom with the statsd service. +static void nativeInit(JNIEnv* env, jobject javaObject) { + gGraphicsStatsServiceObject = env->NewGlobalRef(javaObject); + AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain(); + AStatsManager_PullAtomMetadata_setCoolDownNs(metadata, 10 * 1000000); // 10 milliseconds + AStatsManager_PullAtomMetadata_setTimeoutNs(metadata, 2 * NS_PER_SEC); // 2 seconds + + AStatsManager_registerPullAtomCallback(android::util::GRAPHICS_STATS, + &graphicsStatsPullCallback, metadata, nullptr); + + AStatsManager_PullAtomMetadata_release(metadata); +} + +static void nativeDestructor(JNIEnv* env, jobject javaObject) { + AStatsManager_unregisterPullAtomCallback(android::util::GRAPHICS_STATS); + env->DeleteGlobalRef(gGraphicsStatsServiceObject); + gGraphicsStatsServiceObject = nullptr; +} + +static const JNINativeMethod sMethods[] = + {{"nGetAshmemSize", "()I", (void*)getAshmemSize}, + {"nCreateDump", "(IZ)J", (void*)createDump}, + {"nAddToDump", "(JLjava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)addToDump}, + {"nAddToDump", "(JLjava/lang/String;)V", (void*)addFileToDump}, + {"nFinishDump", "(J)V", (void*)finishDump}, + {"nFinishDumpInMemory", "(JJZ)V", (void*)finishDumpInMemory}, + {"nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)saveBuffer}, + {"nativeInit", "()V", (void*)nativeInit}, + {"nativeDestructor", "()V", (void*)nativeDestructor}}; + +int register_android_graphics_GraphicsStatsService(JNIEnv* env) { + jclass graphicsStatsService_class = + FindClassOrDie(env, "android/graphics/GraphicsStatsService"); + gGraphicsStatsService_pullGraphicsStatsMethodID = + GetMethodIDOrDie(env, graphicsStatsService_class, "pullGraphicsStats", "(ZJ)V"); + return jniRegisterNativeMethods(env, "android/graphics/GraphicsStatsService", sMethods, + NELEM(sMethods)); +} + +} // namespace android diff --git a/core/jni/android/graphics/fonts/Font.cpp b/core/jni/android/graphics/fonts/Font.cpp index bb0654d255c0..8d84e870d205 100644 --- a/core/jni/android/graphics/fonts/Font.cpp +++ b/core/jni/android/graphics/fonts/Font.cpp @@ -33,8 +33,8 @@ #include <hwui/MinikinSkia.h> #include <hwui/Typeface.h> -#include <utils/FatVector.h> #include <minikin/FontFamily.h> +#include <ui/FatVector.h> #include <memory> @@ -157,7 +157,7 @@ static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jo sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize, release_global_ref, reinterpret_cast<void*>(fontRef))); - uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes; + FatVector<SkFontArguments::Axis, 2> skiaAxes; for (const auto& axis : builder->axes) { skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value}); } diff --git a/core/proto/android/app/appexitinfo.proto b/core/proto/android/app/appexitinfo.proto index e23f150fab25..6a4922000805 100644 --- a/core/proto/android/app/appexitinfo.proto +++ b/core/proto/android/app/appexitinfo.proto @@ -178,8 +178,8 @@ message ApplicationExitInfoProto { } optional Importance importance = 10; - optional int32 pss = 11; - optional int32 rss = 12; + optional int64 pss = 11; + optional int64 rss = 12; optional int64 timestamp = 13; optional string description = 14; } diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index c14d99c5d3fb..cc257973b860 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -708,6 +708,12 @@ enum Action { // ACTION: Deny "Access all files" for an app APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_DENY = 1731; + + // ACTION: Battery feature usage + ACTION_BATTERY_OPTION_FEATURE_USAGE = 1732; + + // ACTION: Battery feature runtime event + ACTION_BATTERY_OPTION_RUNTIME_EVENT = 1733; } /** diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index 303d62dbb30a..546c5a092a50 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -219,12 +219,8 @@ message ConstantsProto { // The maximum number of background jobs we allow when the system is in a // critical memory state. optional int32 bg_critical_job_count = 14; - // The maximum number of times we allow a job to have itself rescheduled - // before giving up on it, for standard jobs. - optional int32 max_standard_reschedule_count = 15; - // The maximum number of times we allow a job to have itself rescheduled - // before giving up on it, for jobs that are executing work. - optional int32 max_work_reschedule_count = 16; + reserved 15; // max_standard_reschedule_count + reserved 16; // max_work_reschedule_count // The minimum backoff time to allow for linear backoff. optional int64 min_linear_backoff_time_ms = 17; // The minimum backoff time to allow for exponential backoff. diff --git a/core/proto/android/service/OWNERS b/core/proto/android/service/OWNERS new file mode 100644 index 000000000000..70cb50f75362 --- /dev/null +++ b/core/proto/android/service/OWNERS @@ -0,0 +1 @@ +per-file sensor_service.proto = arthuri@google.com, bduddie@google.com, stange@google.com diff --git a/core/proto/android/service/sensor_service.proto b/core/proto/android/service/sensor_service.proto index 8598f86a7f28..48f6670b59fe 100644 --- a/core/proto/android/service/sensor_service.proto +++ b/core/proto/android/service/sensor_service.proto @@ -39,7 +39,7 @@ message SensorServiceProto { OP_MODE_RESTRICTED = 2; OP_MODE_DATA_INJECTION = 3; } - + optional sint32 init_status = 16; optional int64 current_time_ms = 1; optional SensorDeviceProto sensor_device = 2; optional SensorListProto sensors = 3; @@ -56,6 +56,8 @@ message SensorServiceProto { repeated SensorEventConnectionProto active_connections = 13; repeated SensorDirectConnectionProto direct_connections = 14; repeated SensorRegistrationInfoProto previous_registrations = 15; + + // Next tag: 17 } // Proto dump of android::SensorDevice diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 6d63a532ae14..ff696715e94d 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1535,7 +1535,7 @@ @hide --> <permission android:name="android.permission.ACCESS_CONTEXT_HUB" - android:protectionLevel="signature" /> + android:protectionLevel="signature|privileged" /> <uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB"/> <!-- @SystemApi Allows an application to create mock location providers for testing. diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml index 46e8f64753ac..b01eb3944b50 100644 --- a/core/res/res/drawable-nodpi/platlogo.xml +++ b/core/res/res/drawable-nodpi/platlogo.xml @@ -1,31 +1,50 @@ -<!-- -Copyright (C) 2020 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. ---> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="240dp" - android:height="240dp" - android:viewportWidth="24" - android:viewportHeight="24"> + android:width="512dp" + android:height="512dp" + android:viewportWidth="512" + android:viewportHeight="512"> <path - android:fillColor="#000" - android:pathData="M16 4c-2.2 0-4 1.8-4 4v4H4V8c0-2.2 1.8-4 4-4h8z"/> + android:fillColor="#F86734" + android:pathData="M416.23 236.62h-10.67c-1.46 0-2.65-1.19-2.65-2.65v-9.85c0-1.47 1.19-2.65 2.65-2.65h23.37c1.47 0 2.66 1.19 2.66 2.65v66.9c0 1.46-1.2 2.65-2.66 2.65H418.9c-1.47 0-2.66-1.19-2.66-2.65v-54.4z"/> <path - android:fillColor="#000" - android:pathData="M8 20c2.2 0 4-1.8 4-4v-4H4v8h4z"/> + android:fillColor="#F86734" + android:pathData="M455.51 236.62h-10.67c-1.47 0-2.65-1.19-2.65-2.65v-9.85c0-1.47 1.18-2.65 2.65-2.65h23.37c1.47 0 2.66 1.19 2.66 2.65v66.9c0 1.46-1.2 2.65-2.66 2.65h-10.05c-1.46 0-2.65-1.19-2.65-2.65v-54.4z"/> <path - android:fillColor="#80000000" - android:pathData="M16 12c2.2 0 4-1.8 4-4V4h-8v8h4z"/> + android:fillColor="#D6F0FF" + android:pathData="M364.12 400.25a4.34 4.34 0 1 0 0 8.68a4.34 4.34 0 1 0 0-8.68z"/> + <path + android:fillColor="#D6F0FF" + android:pathData="M275.46 433.53a4.84 4.84 0 1 0 0 9.68a4.84 4.84 0 1 0 0-9.68z"/> + <path + android:fillColor="#D6F0FF" + android:pathData="M184.52 418.83a5.36 5.36 0 1 0 0 10.72a5.36 5.36 0 1 0 0-10.72z"/> + <path + android:fillColor="#D6F0FF" + android:pathData="M110.42 359.19a5.89 5.89 0 1 0 0 11.78a5.89 5.89 0 1 0 0-11.78z"/> + <path + android:fillColor="#D6F0FF" + android:pathData="M75.94 270.17a6.43 6.43 0 1 0 0 12.86a6.43 6.43 0 1 0 0-12.86z"/> + <path + android:fillColor="#D6F0FF" + android:pathData="M89.48 178.57a6.98 6.98 0 1 0 0 13.96a6.98 6.98 0 1 0 0-13.96z"/> + <path + android:fillColor="#D6F0FF" + android:pathData="M147.97 103.54a7.54 7.54 0 1 0 0 15.08a7.54 7.54 0 1 0 0-15.08z"/> + <path + android:fillColor="#D6F0FF" + android:pathData="M236.63 66.7a8.1 8.1 0 1 0 0 16.2a8.1 8.1 0 1 0 0-16.2z"/> + <path + android:fillColor="#D6F0FF" + android:pathData="M327.09 78.3a8.66 8.66 0 1 0 0 17.32a8.66 8.66 0 1 0 0-17.32z"/> + <path + android:fillColor="#D6F0FF" + android:pathData="M401.05 136.97a9.22 9.22 0 1 0 0 18.44a9.22 9.22 0 1 0 0-18.44z"/> + <group> + <path + android:fillColor="#3DDB85" + android:pathData="M255.45 129.46a128.11 128.11 0 1 0 0 256.22a128.11 128.11 0 1 0 0-256.22z"/> + <path + android:fillColor="#FFF" + android:pathData="M339.23 236.09a21.48 21.48 0 1 0 0 42.96a21.48 21.48 0 1 0 0-42.96z"/> + </group> </vector> - diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml index 0e9aab2ab59d..700781b1d0b1 100644 --- a/core/res/res/drawable-nodpi/stat_sys_adb.xml +++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml @@ -1,17 +1,17 @@ -<!-- -Copyright (C) 2020 The Android Open Source Project +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2020 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 + 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 + 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. + 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. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" @@ -19,12 +19,22 @@ Copyright (C) 2020 The Android Open Source Project android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="#000" - android:pathData="M16 4c-2.2 0-4 1.8-4 4v4H4V8c0-2.2 1.8-4 4-4h8z"/> - <path - android:fillColor="#000" - android:pathData="M8 20c2.2 0 4-1.8 4-4v-4H4v8h4z"/> - <path - android:fillColor="#80000000" - android:pathData="M16 12c2.2 0 4-1.8 4-4V4h-8v8h4z"/> + android:fillColor="#FFFFFF" + android:pathData=" +M 12,1 +A 11 11 0 0 0 1,12 +A 11 11 0 1 0 12,1 +Z + +M 12.5,8 +a 3,3 0 0 1 6,0 +a 3,3 0 0 1 -6,0 +Z + +M 5.5,8 +a 3,3 0 0 1 6,0 +l 0,8 +a 3,3 0 0 1 -6,0 +Z +"/> </vector> diff --git a/core/res/res/drawable/tab_indicator_resolver.xml b/core/res/res/drawable/tab_indicator_resolver.xml new file mode 100644 index 000000000000..ff16d81a6383 --- /dev/null +++ b/core/res/res/drawable/tab_indicator_resolver.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 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. +--> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" + android:paddingMode="nest"> + <item> + <ripple android:color="@color/tab_highlight_material"> + <item android:id="@id/mask"> + <color android:color="@color/white" /> + </item> + </ripple> + </item> + <item android:gravity="bottom"> + <shape android:shape="rectangle" + android:tint="@color/resolver_tabs_active_color"> + <size android:height="2dp" /> + <solid android:color="@color/tab_indicator_material" /> + </shape> + </item> + <item android:bottom="2dp" + android:drawable="@color/transparent" /> +</layer-list> diff --git a/core/res/res/layout/tab_indicator_resolver.xml b/core/res/res/layout/tab_indicator_resolver.xml new file mode 100644 index 000000000000..2038da656ee3 --- /dev/null +++ b/core/res/res/layout/tab_indicator_resolver.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="?android:attr/actionBarSize" + android:orientation="horizontal" + style="@android:style/Widget.Material.Resolver.Tab"> + + <ImageView + android:id="@android:id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:visibility="gone" /> + + <TextView + android:id="@android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:textAllCaps="false" + style="@android:style/Widget.Material.TabText" /> + +</LinearLayout> diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml index c5e72f012a21..33caeb65c2f8 100644 --- a/core/res/res/values-night/colors.xml +++ b/core/res/res/values-night/colors.xml @@ -32,4 +32,6 @@ <color name="chooser_row_divider">@color/list_divider_color_dark</color> <color name="chooser_gradient_background">@color/loading_gradient_background_color_dark</color> <color name="chooser_gradient_highlight">@color/loading_gradient_highlight_color_dark</color> + + <color name="resolver_tabs_active_color">#FF8AB4F8</color> </resources> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index cef21db1e0f8..81ec27841aa7 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -1679,6 +1679,15 @@ easier. <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item> <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item> <item name="navigationBarColor">@android:color/transparent</item> + <item name="tabWidgetStyle">@style/Widget.DeviceDefault.Resolver.TabWidget</item> + </style> + + <style name="Widget.DeviceDefault.Resolver.TabWidget" parent="Widget.DeviceDefault.TabWidget"> + <item name="tabLayout">@layout/tab_indicator_resolver</item> + </style> + + <style name="Widget.Material.Resolver.Tab" parent="Widget.Material.Tab"> + <item name="background">@drawable/tab_indicator_resolver</item> </style> <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon"> diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index 59335a595334..718ca46a4f18 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -1330,6 +1330,12 @@ android:process=":FakeProvider"> </provider> + <provider + android:name="android.content.SlowProvider" + android:authorities="android.content.SlowProvider" + android:process=":SlowProvider"> + </provider> + <!-- Application components used for os tests --> <service android:name="android.os.MessengerService" diff --git a/core/tests/coretests/src/android/app/NotificationHistoryTest.java b/core/tests/coretests/src/android/app/NotificationHistoryTest.java index 0a21875fd77d..d1608d055604 100644 --- a/core/tests/coretests/src/android/app/NotificationHistoryTest.java +++ b/core/tests/coretests/src/android/app/NotificationHistoryTest.java @@ -234,6 +234,40 @@ public class NotificationHistoryTest { } @Test + public void testRemoveNotificationFromWrite() { + NotificationHistory history = new NotificationHistory(); + + List<HistoricalNotification> postRemoveExpectedEntries = new ArrayList<>(); + List<String> postRemoveExpectedStrings = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + HistoricalNotification n = getHistoricalNotification("pkg", i); + + if (987654323 != n.getPostedTimeMs()) { + postRemoveExpectedStrings.add(n.getPackage()); + postRemoveExpectedStrings.add(n.getChannelName()); + postRemoveExpectedStrings.add(n.getChannelId()); + postRemoveExpectedEntries.add(n); + } + + history.addNotificationToWrite(n); + } + + history.poolStringsFromNotifications(); + + assertThat(history.getNotificationsToWrite().size()).isEqualTo(10); + // 1 package name and 10 unique channel names and ids + assertThat(history.getPooledStringsToWrite().length).isEqualTo(21); + + history.removeNotificationFromWrite("pkg", 987654323); + + + // 1 package names and 9 * 2 unique channel names and ids + assertThat(history.getPooledStringsToWrite().length).isEqualTo(19); + assertThat(history.getNotificationsToWrite()) + .containsExactlyElementsIn(postRemoveExpectedEntries); + } + + @Test public void testParceling() { NotificationHistory history = new NotificationHistory(); diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java index 9dcce1e51e0b..6dc7392945d8 100644 --- a/core/tests/coretests/src/android/content/ContentResolverTest.java +++ b/core/tests/coretests/src/android/content/ContentResolverTest.java @@ -209,4 +209,13 @@ public class ContentResolverTest { String type = mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote")); assertEquals("fake/remote", type); } + + + @Test + public void testGetType_slowProvider() { + // This provider is running in a different process and is intentionally slow to start. + // We are trying to confirm that it does not cause an ANR + String type = mResolver.getType(Uri.parse("content://android.content.SlowProvider")); + assertEquals("slow", type); + } } diff --git a/core/tests/coretests/src/android/content/SlowProvider.java b/core/tests/coretests/src/android/content/SlowProvider.java new file mode 100644 index 000000000000..aba32e836e80 --- /dev/null +++ b/core/tests/coretests/src/android/content/SlowProvider.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 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.content; + +import android.database.Cursor; +import android.net.Uri; + +/** + * A dummy content provider for tests. This provider runs in a different process from the test and + * is intentionally slow. + */ +public class SlowProvider extends ContentProvider { + + private static final int ON_CREATE_LATENCY_MILLIS = 3000; + + @Override + public boolean onCreate() { + try { + Thread.sleep(ON_CREATE_LATENCY_MILLIS); + } catch (InterruptedException e) { + // Ignore + } + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + return null; + } + + @Override + public String getType(Uri uri) { + return "slow"; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + return 0; + } +} diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/graphics/java/android/graphics/GraphicsStatsService.java index 5179fa7a6eb5..8dfd6ee92a9a 100644 --- a/services/core/java/com/android/server/GraphicsStatsService.java +++ b/graphics/java/android/graphics/GraphicsStatsService.java @@ -14,8 +14,9 @@ * limitations under the License. */ -package com.android.server; +package android.graphics; +import android.annotation.SystemApi; import android.app.AlarmManager; import android.app.AppOpsManager; import android.content.Context; @@ -26,13 +27,14 @@ import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; -import android.os.MemoryFile; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; +import android.os.SharedMemory; import android.os.Trace; import android.os.UserHandle; +import android.system.ErrnoException; import android.util.Log; import android.view.IGraphicsStats; import android.view.IGraphicsStatsCallback; @@ -45,6 +47,7 @@ import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -84,8 +87,8 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { // This isn't static because we need this to happen after registerNativeMethods, however // the class is loaded (and thus static ctor happens) before that occurs. - private final int ASHMEM_SIZE = nGetAshmemSize(); - private final byte[] ZERO_DATA = new byte[ASHMEM_SIZE]; + private final int mAshmemSize = nGetAshmemSize(); + private final byte[] mZeroData = new byte[mAshmemSize]; private final Context mContext; private final AppOpsManager mAppOps; @@ -97,6 +100,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { private Handler mWriteOutHandler; private boolean mRotateIsScheduled = false; + @SystemApi public GraphicsStatsService(Context context) { mContext = context; mAppOps = context.getSystemService(AppOpsManager.class); @@ -108,7 +112,8 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { throw new IllegalStateException("Graphics stats directory does not exist: " + mGraphicsStatsDir.getAbsolutePath()); } - HandlerThread bgthread = new HandlerThread("GraphicsStats-disk", Process.THREAD_PRIORITY_BACKGROUND); + HandlerThread bgthread = new HandlerThread("GraphicsStats-disk", + Process.THREAD_PRIORITY_BACKGROUND); bgthread.start(); mWriteOutHandler = new Handler(bgthread.getLooper(), new Handler.Callback() { @@ -159,7 +164,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { active.mCallback.onRotateGraphicsStatsBuffer(); } catch (RemoteException e) { Log.w(TAG, String.format("Failed to notify '%s' (pid=%d) to rotate buffers", - active.mInfo.packageName, active.mPid), e); + active.mInfo.mPackageName, active.mPid), e); } } // Give a few seconds for everyone to rotate before doing the cleanup @@ -167,8 +172,8 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { } @Override - public ParcelFileDescriptor requestBufferForProcess(String packageName, IGraphicsStatsCallback token) - throws RemoteException { + public ParcelFileDescriptor requestBufferForProcess(String packageName, + IGraphicsStatsCallback token) throws RemoteException { int uid = Binder.getCallingUid(); int pid = Binder.getCallingPid(); ParcelFileDescriptor pfd = null; @@ -196,7 +201,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { // current day. // This method is invoked from native code only. @SuppressWarnings({"UnusedDeclaration"}) - private long pullGraphicsStats(boolean lastFullDay) throws RemoteException { + private void pullGraphicsStats(boolean lastFullDay, long pulledData) throws RemoteException { int uid = Binder.getCallingUid(); // DUMP and PACKAGE_USAGE_STATS permissions are required to invoke this method. @@ -213,13 +218,13 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { long callingIdentity = Binder.clearCallingIdentity(); try { - return pullGraphicsStatsImpl(lastFullDay); + pullGraphicsStatsImpl(lastFullDay, pulledData); } finally { Binder.restoreCallingIdentity(callingIdentity); } } - private long pullGraphicsStatsImpl(boolean lastFullDay) { + private void pullGraphicsStatsImpl(boolean lastFullDay, long pulledData) { long targetDay; if (lastFullDay) { // Get stats from yesterday. Stats stay constant, because the day is over. @@ -235,7 +240,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { buffers = new ArrayList<>(mActive.size()); for (int i = 0; i < mActive.size(); i++) { ActiveBuffer buffer = mActive.get(i); - if (buffer.mInfo.startTime == targetDay) { + if (buffer.mInfo.mStartTime == targetDay) { try { buffers.add(new HistoricalBuffer(buffer)); } catch (IOException ex) { @@ -267,18 +272,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { } } } finally { - return nFinishDumpInMemory(dump); - } - } - - private ParcelFileDescriptor getPfd(MemoryFile file) { - try { - if (!file.getFileDescriptor().valid()) { - throw new IllegalStateException("Invalid file descriptor"); - } - return ParcelFileDescriptor.dup(file.getFileDescriptor()); - } catch (IOException ex) { - throw new IllegalStateException("Failed to get PFD from memory file", ex); + nFinishDumpInMemory(dump, pulledData, lastFullDay); } } @@ -286,7 +280,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { int uid, int pid, String packageName, long versionCode) throws RemoteException { ActiveBuffer buffer = fetchActiveBuffersLocked(token, uid, pid, packageName, versionCode); scheduleRotateLocked(); - return getPfd(buffer.mProcessBuffer); + return buffer.getPfd(); } private Calendar normalizeDate(long timestamp) { @@ -301,13 +295,15 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { private File pathForApp(BufferInfo info) { String subPath = String.format("%d/%s/%d/total", - normalizeDate(info.startTime).getTimeInMillis(), info.packageName, info.versionCode); + normalizeDate(info.mStartTime).getTimeInMillis(), info.mPackageName, + info.mVersionCode); return new File(mGraphicsStatsDir, subPath); } private void saveBuffer(HistoricalBuffer buffer) { if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) { - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "saving graphicsstats for " + buffer.mInfo.packageName); + Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, + "saving graphicsstats for " + buffer.mInfo.mPackageName); } synchronized (mFileAccessLock) { File path = pathForApp(buffer.mInfo); @@ -317,8 +313,9 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { Log.w(TAG, "Unable to create path: '" + parent.getAbsolutePath() + "'"); return; } - nSaveBuffer(path.getAbsolutePath(), buffer.mInfo.packageName, buffer.mInfo.versionCode, - buffer.mInfo.startTime, buffer.mInfo.endTime, buffer.mData); + nSaveBuffer(path.getAbsolutePath(), buffer.mInfo.mPackageName, + buffer.mInfo.mVersionCode, buffer.mInfo.mStartTime, buffer.mInfo.mEndTime, + buffer.mData); } Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); } @@ -365,7 +362,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { HistoricalBuffer data = new HistoricalBuffer(buffer); Message.obtain(mWriteOutHandler, SAVE_BUFFER, data).sendToTarget(); } catch (IOException e) { - Log.w(TAG, "Failed to copy graphicsstats from " + buffer.mInfo.packageName, e); + Log.w(TAG, "Failed to copy graphicsstats from " + buffer.mInfo.mPackageName, e); } buffer.closeAllBuffers(); } @@ -386,7 +383,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { if (buffer.mPid == pid && buffer.mUid == uid) { // If the buffer is too old we remove it and return a new one - if (buffer.mInfo.startTime < today) { + if (buffer.mInfo.mStartTime < today) { buffer.binderDied(); break; } else { @@ -410,8 +407,8 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { HistoricalBuffer buffer = buffers.get(i); File path = pathForApp(buffer.mInfo); skipFiles.add(path); - nAddToDump(dump, path.getAbsolutePath(), buffer.mInfo.packageName, - buffer.mInfo.versionCode, buffer.mInfo.startTime, buffer.mInfo.endTime, + nAddToDump(dump, path.getAbsolutePath(), buffer.mInfo.mPackageName, + buffer.mInfo.mVersionCode, buffer.mInfo.mStartTime, buffer.mInfo.mEndTime, buffer.mData); } return skipFiles; @@ -478,20 +475,20 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { long versionCode, long startTime, long endTime, byte[] data); private static native void nAddToDump(long dump, String path); private static native void nFinishDump(long dump); - private static native long nFinishDumpInMemory(long dump); + private static native void nFinishDumpInMemory(long dump, long pulledData, boolean lastFullDay); private static native void nSaveBuffer(String path, String packageName, long versionCode, long startTime, long endTime, byte[] data); private final class BufferInfo { - final String packageName; - final long versionCode; - long startTime; - long endTime; + final String mPackageName; + final long mVersionCode; + long mStartTime; + long mEndTime; BufferInfo(String packageName, long versionCode, long startTime) { - this.packageName = packageName; - this.versionCode = versionCode; - this.startTime = startTime; + this.mPackageName = packageName; + this.mVersionCode = versionCode; + this.mStartTime = startTime; } } @@ -501,7 +498,8 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { final int mPid; final IGraphicsStatsCallback mCallback; final IBinder mToken; - MemoryFile mProcessBuffer; + SharedMemory mProcessBuffer; + ByteBuffer mMapping; ActiveBuffer(IGraphicsStatsCallback token, int uid, int pid, String packageName, long versionCode) @@ -512,8 +510,14 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { mCallback = token; mToken = mCallback.asBinder(); mToken.linkToDeath(this, 0); - mProcessBuffer = new MemoryFile("GFXStats-" + pid, ASHMEM_SIZE); - mProcessBuffer.writeBytes(ZERO_DATA, 0, 0, ASHMEM_SIZE); + try { + mProcessBuffer = SharedMemory.create("GFXStats-" + pid, mAshmemSize); + mMapping = mProcessBuffer.mapReadWrite(); + } catch (ErrnoException ex) { + ex.rethrowAsIOException(); + } + mMapping.position(0); + mMapping.put(mZeroData, 0, mAshmemSize); } @Override @@ -523,20 +527,40 @@ public class GraphicsStatsService extends IGraphicsStats.Stub { } void closeAllBuffers() { + if (mMapping != null) { + SharedMemory.unmap(mMapping); + mMapping = null; + } if (mProcessBuffer != null) { mProcessBuffer.close(); mProcessBuffer = null; } } + + ParcelFileDescriptor getPfd() { + try { + return mProcessBuffer.getFdDup(); + } catch (IOException ex) { + throw new IllegalStateException("Failed to get PFD from memory file", ex); + } + } + + void readBytes(byte[] buffer, int count) throws IOException { + if (mMapping == null) { + throw new IOException("SharedMemory has been deactivated"); + } + mMapping.position(0); + mMapping.get(buffer, 0, count); + } } private final class HistoricalBuffer { final BufferInfo mInfo; - final byte[] mData = new byte[ASHMEM_SIZE]; + final byte[] mData = new byte[mAshmemSize]; HistoricalBuffer(ActiveBuffer active) throws IOException { mInfo = active.mInfo; - mInfo.endTime = System.currentTimeMillis(); - active.mProcessBuffer.readBytes(mData, 0, 0, ASHMEM_SIZE); + mInfo.mEndTime = System.currentTimeMillis(); + active.readBytes(mData, mAshmemSize); } } } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 51270f5bcebd..301d1afc6c13 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -92,9 +92,12 @@ cc_defaults { "libandroidfw", "libcrypto", "libsync", + "libstatspull", + "libstatssocket", ], static_libs: [ "libEGL_blobCache", + "libprotoutil", ], }, host: { diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 6761435a8171..31e45558139d 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -27,7 +27,6 @@ #include "DamageAccumulator.h" #include "pipeline/skia/SkiaDisplayList.h" #endif -#include "utils/FatVector.h" #include "utils/MathUtils.h" #include "utils/StringUtils.h" #include "utils/TraceUtils.h" @@ -37,6 +36,7 @@ #include <atomic> #include <sstream> #include <string> +#include <ui/FatVector.h> namespace android { namespace uirenderer { diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index d55e5b0ce836..c0ec2174bb35 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -27,6 +27,8 @@ #include <androidfw/ResourceTypes.h> +#include <ui/FatVector.h> + #include "AnimatorManager.h" #include "CanvasTransform.h" #include "Debug.h" @@ -35,7 +37,6 @@ #include "RenderProperties.h" #include "pipeline/skia/SkiaDisplayList.h" #include "pipeline/skia/SkiaLayer.h" -#include "utils/FatVector.h" #include <vector> diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h index cfc0f9b258da..d669f84c5ee2 100644 --- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h +++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h @@ -21,7 +21,7 @@ #include <SkCanvas.h> #include <SkDrawable.h> -#include <utils/FatVector.h> +#include <ui/FatVector.h> namespace android { namespace uirenderer { diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index cae3e3b5188c..206b58f62ea7 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -27,7 +27,6 @@ #include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/SkiaVulkanPipeline.h" #include "renderstate/RenderState.h" -#include "utils/FatVector.h" #include "utils/TimeUtils.h" #include "utils/TraceUtils.h" @@ -40,6 +39,8 @@ #include <utils/Mutex.h> #include <thread> +#include <ui/FatVector.h> + namespace android { namespace uirenderer { namespace renderthread { diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index a5355fc3499d..ba70afc8b8d2 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -23,13 +23,13 @@ #include <GrContext.h> #include <GrTypes.h> #include <android/sync.h> +#include <ui/FatVector.h> #include <vk/GrVkExtensions.h> #include <vk/GrVkTypes.h> #include "Properties.h" #include "RenderThread.h" #include "renderstate/RenderState.h" -#include "utils/FatVector.h" #include "utils/TraceUtils.h" namespace android { diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp index c4186174b637..644d5fbd5bf9 100644 --- a/libs/hwui/service/GraphicsStatsService.cpp +++ b/libs/hwui/service/GraphicsStatsService.cpp @@ -26,9 +26,9 @@ #include <sys/types.h> #include <unistd.h> -#include <algorithm> -#include <map> -#include <vector> +#include <android/util/ProtoOutputStream.h> +#include <stats_event.h> +#include <statslog.h> #include "JankTracker.h" #include "protos/graphicsstats.pb.h" @@ -61,7 +61,7 @@ public: } } bool valid() { return mFd != -1; } - operator int() { return mFd; } // NOLINT(google-explicit-constructor) + operator int() { return mFd; } // NOLINT(google-explicit-constructor) private: int mFd; @@ -485,79 +485,82 @@ void GraphicsStatsService::finishDump(Dump* dump) { delete dump; } -class MemOutputStreamLite : public io::ZeroCopyOutputStream { -public: - explicit MemOutputStreamLite() : mCopyAdapter(), mImpl(&mCopyAdapter) {} - virtual ~MemOutputStreamLite() {} - - virtual bool Next(void** data, int* size) override { return mImpl.Next(data, size); } - - virtual void BackUp(int count) override { mImpl.BackUp(count); } - - virtual int64 ByteCount() const override { return mImpl.ByteCount(); } - - bool Flush() { return mImpl.Flush(); } - - void copyData(const DumpMemoryFn& reader, void* param1, void* param2) { - int bufferOffset = 0; - int totalSize = mCopyAdapter.mBuffersSize - mCopyAdapter.mCurrentBufferUnusedSize; - int totalDataLeft = totalSize; - for (auto& it : mCopyAdapter.mBuffers) { - int bufferSize = std::min(totalDataLeft, (int)it.size()); // last buffer is not full - reader(it.data(), bufferOffset, bufferSize, totalSize, param1, param2); - bufferOffset += bufferSize; - totalDataLeft -= bufferSize; - } - } - -private: - struct MemAdapter : public io::CopyingOutputStream { - // Data is stored in an array of buffers. - // JNI SetByteArrayRegion assembles data in one continuous Java byte[] buffer. - std::vector<std::vector<unsigned char>> mBuffers; - int mBuffersSize = 0; // total bytes allocated in mBuffers - int mCurrentBufferUnusedSize = 0; // unused bytes in the last buffer mBuffers.back() - unsigned char* mCurrentBuffer = nullptr; // pointer to next free byte in mBuffers.back() +using namespace google::protobuf; - explicit MemAdapter() {} - virtual ~MemAdapter() {} +// Field ids taken from FrameTimingHistogram message in atoms.proto +#define TIME_MILLIS_BUCKETS_FIELD_NUMBER 1 +#define FRAME_COUNTS_FIELD_NUMBER 2 + +static void writeCpuHistogram(AStatsEvent* event, + const uirenderer::protos::GraphicsStatsProto& stat) { + util::ProtoOutputStream proto; + for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) { + auto& bucket = stat.histogram(bucketIndex); + proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED | + TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */, + (int)bucket.render_millis()); + } + for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) { + auto& bucket = stat.histogram(bucketIndex); + proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED | + FRAME_COUNTS_FIELD_NUMBER /* field id */, + (long long)bucket.frame_count()); + } + std::vector<uint8_t> outVector; + proto.serializeToVector(&outVector); + AStatsEvent_writeByteArray(event, outVector.data(), outVector.size()); +} - virtual bool Write(const void* buffer, int size) override { - while (size > 0) { - if (0 == mCurrentBufferUnusedSize) { - mCurrentBufferUnusedSize = - std::max(size, mBuffersSize ? 2 * mBuffersSize : 10000); - mBuffers.emplace_back(); - mBuffers.back().resize(mCurrentBufferUnusedSize); - mCurrentBuffer = mBuffers.back().data(); - mBuffersSize += mCurrentBufferUnusedSize; - } - int dataMoved = std::min(mCurrentBufferUnusedSize, size); - memcpy(mCurrentBuffer, buffer, dataMoved); - mCurrentBufferUnusedSize -= dataMoved; - mCurrentBuffer += dataMoved; - buffer = reinterpret_cast<const unsigned char*>(buffer) + dataMoved; - size -= dataMoved; - } - return true; - } - }; +static void writeGpuHistogram(AStatsEvent* event, + const uirenderer::protos::GraphicsStatsProto& stat) { + util::ProtoOutputStream proto; + for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) { + auto& bucket = stat.gpu_histogram(bucketIndex); + proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED | + TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */, + (int)bucket.render_millis()); + } + for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) { + auto& bucket = stat.gpu_histogram(bucketIndex); + proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED | + FRAME_COUNTS_FIELD_NUMBER /* field id */, + (long long)bucket.frame_count()); + } + std::vector<uint8_t> outVector; + proto.serializeToVector(&outVector); + AStatsEvent_writeByteArray(event, outVector.data(), outVector.size()); +} - MemOutputStreamLite::MemAdapter mCopyAdapter; - io::CopyingOutputStreamAdaptor mImpl; -}; -void GraphicsStatsService::finishDumpInMemory(Dump* dump, const DumpMemoryFn& reader, void* param1, - void* param2) { - MemOutputStreamLite stream; +void GraphicsStatsService::finishDumpInMemory(Dump* dump, AStatsEventList* data, + bool lastFullDay) { dump->updateProto(); - bool success = dump->proto().SerializeToZeroCopyStream(&stream) && stream.Flush(); - delete dump; - if (!success) { - return; + auto& serviceDump = dump->proto(); + for (int stat_index = 0; stat_index < serviceDump.stats_size(); stat_index++) { + auto& stat = serviceDump.stats(stat_index); + AStatsEvent* event = AStatsEventList_addStatsEvent(data); + AStatsEvent_setAtomId(event, android::util::GRAPHICS_STATS); + AStatsEvent_writeString(event, stat.package_name().c_str()); + AStatsEvent_writeInt64(event, (int64_t)stat.version_code()); + AStatsEvent_writeInt64(event, (int64_t)stat.stats_start()); + AStatsEvent_writeInt64(event, (int64_t)stat.stats_end()); + AStatsEvent_writeInt32(event, (int32_t)stat.pipeline()); + AStatsEvent_writeInt32(event, (int32_t)stat.summary().total_frames()); + AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_vsync_count()); + AStatsEvent_writeInt32(event, (int32_t)stat.summary().high_input_latency_count()); + AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_ui_thread_count()); + AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_bitmap_upload_count()); + AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_draw_count()); + AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_deadline_count()); + writeCpuHistogram(event, stat); + writeGpuHistogram(event, stat); + // TODO: fill in UI mainline module version, when the feature is available. + AStatsEvent_writeInt64(event, (int64_t)0); + AStatsEvent_writeBool(event, !lastFullDay); + AStatsEvent_build(event); } - stream.copyData(reader, param1, param2); } + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/service/GraphicsStatsService.h b/libs/hwui/service/GraphicsStatsService.h index 4bed96330a52..59e21d039c9d 100644 --- a/libs/hwui/service/GraphicsStatsService.h +++ b/libs/hwui/service/GraphicsStatsService.h @@ -20,6 +20,7 @@ #include "JankTracker.h" #include "utils/Macros.h" +#include <stats_pull_atom_callback.h> namespace android { namespace uirenderer { @@ -27,9 +28,6 @@ namespace protos { class GraphicsStatsProto; } -typedef void (*DumpMemoryFn)(void* buffer, int bufferOffset, int bufferSize, int totalSize, - void* param1, void* param2); - /* * The exported entry points used by GraphicsStatsService.java in f/b/services/core * @@ -56,8 +54,8 @@ public: int64_t startTime, int64_t endTime, const ProfileData* data); ANDROID_API static void addToDump(Dump* dump, const std::string& path); ANDROID_API static void finishDump(Dump* dump); - ANDROID_API static void finishDumpInMemory(Dump* dump, const DumpMemoryFn& reader, void* param1, - void* param2); + ANDROID_API static void finishDumpInMemory(Dump* dump, AStatsEventList* data, + bool lastFullDay); // Visible for testing static bool parseFromFile(const std::string& path, protos::GraphicsStatsProto* output); diff --git a/libs/hwui/tests/unit/FatVectorTests.cpp b/libs/hwui/tests/unit/FatVectorTests.cpp index 8523e6c9e973..6585a6249b44 100644 --- a/libs/hwui/tests/unit/FatVectorTests.cpp +++ b/libs/hwui/tests/unit/FatVectorTests.cpp @@ -15,7 +15,7 @@ */ #include <gtest/gtest.h> -#include <utils/FatVector.h> +#include <ui/FatVector.h> #include <tests/common/TestUtils.h> diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h deleted file mode 100644 index 8cc4d1010ab6..000000000000 --- a/libs/hwui/utils/FatVector.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2015, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ANDROID_FAT_VECTOR_H -#define ANDROID_FAT_VECTOR_H - -#include "utils/Macros.h" - -#include <stddef.h> -#include <stdlib.h> -#include <utils/Log.h> -#include <type_traits> - -#include <vector> - -namespace android { -namespace uirenderer { - -template <typename T, size_t SIZE> -class InlineStdAllocator { -public: - struct Allocation { - PREVENT_COPY_AND_ASSIGN(Allocation); - - public: - Allocation(){}; - // char array instead of T array, so memory is uninitialized, with no destructors run - char array[sizeof(T) * SIZE]; - bool inUse = false; - }; - - typedef T value_type; // needed to implement std::allocator - typedef T* pointer; // needed to implement std::allocator - - explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {} - InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {} - ~InlineStdAllocator() {} - - T* allocate(size_t num, const void* = 0) { - if (!mAllocation.inUse && num <= SIZE) { - mAllocation.inUse = true; - return (T*)mAllocation.array; - } else { - return (T*)malloc(num * sizeof(T)); - } - } - - void deallocate(pointer p, size_t num) { - if (p == (T*)mAllocation.array) { - mAllocation.inUse = false; - } else { - // 'free' instead of delete here - destruction handled separately - free(p); - } - } - Allocation& mAllocation; -}; - -/** - * std::vector with SIZE elements preallocated into an internal buffer. - * - * Useful for avoiding the cost of malloc in cases where only SIZE or - * fewer elements are needed in the common case. - */ -template <typename T, size_t SIZE> -class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> { -public: - FatVector() - : std::vector<T, InlineStdAllocator<T, SIZE>>( - InlineStdAllocator<T, SIZE>(mAllocation)) { - this->reserve(SIZE); - } - - explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); } - -private: - typename InlineStdAllocator<T, SIZE>::Allocation mAllocation; -}; - -} // namespace uirenderer -} // namespace android - -#endif // ANDROID_FAT_VECTOR_H diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index e4348f2a9b21..3b494e9129db 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -251,19 +251,24 @@ void PointerController::unfade(Transition transition) { void PointerController::setPresentation(Presentation presentation) { AutoMutex _l(mLock); - if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) { - mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources, - &mLocked.animationResources, mLocked.viewport.displayId); + if (mLocked.presentation == presentation) { + return; } - if (mLocked.presentation != presentation) { - mLocked.presentation = presentation; - mLocked.presentationChanged = true; + mLocked.presentation = presentation; + mLocked.presentationChanged = true; - if (presentation != PRESENTATION_SPOT) { - fadeOutAndReleaseAllSpotsLocked(); - } + if (!mLocked.viewport.isValid()) { + return; + } + if (presentation == PRESENTATION_POINTER) { + if (mLocked.additionalMouseResources.empty()) { + mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources, + &mLocked.animationResources, + mLocked.viewport.displayId); + } + fadeOutAndReleaseAllSpotsLocked(); updatePointerLocked(); } } @@ -285,6 +290,9 @@ void PointerController::setSpots(const PointerCoords* spotCoords, #endif AutoMutex _l(mLock); + if (!mLocked.viewport.isValid()) { + return; + } std::vector<Spot*> newSpots; std::map<int32_t, std::vector<Spot*>>::const_iterator iter = @@ -331,6 +339,9 @@ void PointerController::clearSpots() { #endif AutoMutex _l(mLock); + if (!mLocked.viewport.isValid()) { + return; + } fadeOutAndReleaseAllSpotsLocked(); } @@ -752,6 +763,10 @@ void PointerController::fadeOutAndReleaseAllSpotsLocked() { } void PointerController::loadResourcesLocked() REQUIRES(mLock) { + if (!mLocked.viewport.isValid()) { + return; + } + mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId); mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId); diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp index b36406d6a703..a15742671dc7 100644 --- a/libs/input/tests/PointerController_test.cpp +++ b/libs/input/tests/PointerController_test.cpp @@ -39,8 +39,8 @@ enum TestCursorType { using ::testing::AllOf; using ::testing::Field; -using ::testing::NiceMock; using ::testing::Mock; +using ::testing::NiceMock; using ::testing::Return; using ::testing::Test; @@ -57,12 +57,20 @@ public: virtual int32_t getDefaultPointerIconId() override; virtual int32_t getCustomPointerIconId() override; + bool allResourcesAreLoaded(); + bool noResourcesAreLoaded(); + private: void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType); + + bool pointerIconLoaded{false}; + bool pointerResourcesLoaded{false}; + bool additionalMouseResourcesLoaded{false}; }; void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, int32_t) { loadPointerIconForType(icon, CURSOR_TYPE_DEFAULT); + pointerIconLoaded = true; } void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources* outResources, @@ -70,6 +78,7 @@ void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources loadPointerIconForType(&outResources->spotHover, CURSOR_TYPE_HOVER); loadPointerIconForType(&outResources->spotTouch, CURSOR_TYPE_TOUCH); loadPointerIconForType(&outResources->spotAnchor, CURSOR_TYPE_ANCHOR); + pointerResourcesLoaded = true; } void MockPointerControllerPolicyInterface::loadAdditionalMouseResources( @@ -91,6 +100,8 @@ void MockPointerControllerPolicyInterface::loadAdditionalMouseResources( anim.durationPerFrame = 10; (*outResources)[cursorType] = icon; (*outAnimationResources)[cursorType] = anim; + + additionalMouseResourcesLoaded = true; } int32_t MockPointerControllerPolicyInterface::getDefaultPointerIconId() { @@ -101,18 +112,27 @@ int32_t MockPointerControllerPolicyInterface::getCustomPointerIconId() { return CURSOR_TYPE_CUSTOM; } +bool MockPointerControllerPolicyInterface::allResourcesAreLoaded() { + return pointerIconLoaded && pointerResourcesLoaded && additionalMouseResourcesLoaded; +} + +bool MockPointerControllerPolicyInterface::noResourcesAreLoaded() { + return !(pointerIconLoaded || pointerResourcesLoaded || additionalMouseResourcesLoaded); +} + void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* icon, int32_t type) { icon->style = type; std::pair<float, float> hotSpot = getHotSpotCoordinatesForType(type); icon->hotSpotX = hotSpot.first; icon->hotSpotY = hotSpot.second; } - class PointerControllerTest : public Test { protected: PointerControllerTest(); ~PointerControllerTest(); + void ensureDisplayViewportIsSet(); + sp<MockSprite> mPointerSprite; sp<MockPointerControllerPolicyInterface> mPolicy; sp<MockSpriteController> mSpriteController; @@ -141,7 +161,14 @@ PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<Moc .WillOnce(Return(mPointerSprite)); mPointerController = new PointerController(mPolicy, mLooper, mSpriteController); +} + +PointerControllerTest::~PointerControllerTest() { + mRunning.store(false, std::memory_order_relaxed); + mThread.join(); +} +void PointerControllerTest::ensureDisplayViewportIsSet() { DisplayViewport viewport; viewport.displayId = ADISPLAY_ID_DEFAULT; viewport.logicalRight = 1600; @@ -151,11 +178,9 @@ PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<Moc viewport.deviceWidth = 400; viewport.deviceHeight = 300; mPointerController->setDisplayViewport(viewport); -} -PointerControllerTest::~PointerControllerTest() { - mRunning.store(false, std::memory_order_relaxed); - mThread.join(); + // The first call to setDisplayViewport should trigger the loading of the necessary resources. + EXPECT_TRUE(mPolicy->allResourcesAreLoaded()); } void PointerControllerTest::loopThread() { @@ -167,6 +192,7 @@ void PointerControllerTest::loopThread() { } TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) { + ensureDisplayViewportIsSet(); mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_DEFAULT); @@ -181,6 +207,7 @@ TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) { } TEST_F(PointerControllerTest, updatePointerIcon) { + ensureDisplayViewportIsSet(); mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); int32_t type = CURSOR_TYPE_ADDITIONAL; @@ -196,6 +223,7 @@ TEST_F(PointerControllerTest, updatePointerIcon) { } TEST_F(PointerControllerTest, setCustomPointerIcon) { + ensureDisplayViewportIsSet(); mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); int32_t style = CURSOR_TYPE_CUSTOM; @@ -217,4 +245,18 @@ TEST_F(PointerControllerTest, setCustomPointerIcon) { mPointerController->setCustomPointerIcon(icon); } +TEST_F(PointerControllerTest, doesNotGetResourcesBeforeSettingViewport) { + mPointerController->setPresentation(PointerController::PRESENTATION_POINTER); + mPointerController->setSpots(nullptr, nullptr, BitSet32(), -1); + mPointerController->clearSpots(); + mPointerController->setPosition(1.0f, 1.0f); + mPointerController->move(1.0f, 1.0f); + mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); + mPointerController->fade(PointerController::TRANSITION_IMMEDIATE); + + EXPECT_TRUE(mPolicy->noResourcesAreLoaded()); + + ensureDisplayViewportIsSet(); +} + } // namespace android diff --git a/libs/services/Android.bp b/libs/services/Android.bp index 9b047ca22d19..1e621079b532 100644 --- a/libs/services/Android.bp +++ b/libs/services/Android.bp @@ -20,7 +20,6 @@ cc_library_shared { ":IDropBoxManagerService.aidl", "src/content/ComponentName.cpp", "src/os/DropBoxManager.cpp", - "src/os/StatsDimensionsValue.cpp", ], shared_libs: [ diff --git a/libs/services/include/android/os/StatsDimensionsValue.h b/libs/services/include/android/os/StatsDimensionsValue.h deleted file mode 100644 index cc0b05644f2c..000000000000 --- a/libs/services/include/android/os/StatsDimensionsValue.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ -#ifndef STATS_DIMENSIONS_VALUE_H -#define STATS_DIMENSIONS_VALUE_H - -#include <binder/Parcel.h> -#include <binder/Parcelable.h> -#include <binder/Status.h> -#include <utils/String16.h> -#include <vector> - -namespace android { -namespace os { - -// Represents a parcelable object. Used to send data from statsd to StatsCompanionService.java. -class StatsDimensionsValue : public android::Parcelable { -public: - StatsDimensionsValue(); - - StatsDimensionsValue(int32_t field, String16 value); - StatsDimensionsValue(int32_t field, int32_t value); - StatsDimensionsValue(int32_t field, int64_t value); - StatsDimensionsValue(int32_t field, bool value); - StatsDimensionsValue(int32_t field, float value); - StatsDimensionsValue(int32_t field, std::vector<StatsDimensionsValue> value); - - virtual ~StatsDimensionsValue(); - - virtual android::status_t writeToParcel(android::Parcel* out) const override; - virtual android::status_t readFromParcel(const android::Parcel* in) override; - -private: - // Keep constants in sync with android/os/StatsDimensionsValue.java - // and stats_log.proto's DimensionValue. - static const int kStrValueType = 2; - static const int kIntValueType = 3; - static const int kLongValueType = 4; - static const int kBoolValueType = 5; - static const int kFloatValueType = 6; - static const int kTupleValueType = 7; - - int32_t mField; - int32_t mValueType; - - // This isn't very clever, but it isn't used for long-term storage, so it'll do. - String16 mStrValue; - int32_t mIntValue; - int64_t mLongValue; - bool mBoolValue; - float mFloatValue; - std::vector<StatsDimensionsValue> mTupleValue; -}; - -} // namespace os -} // namespace android - -#endif // STATS_DIMENSIONS_VALUE_H diff --git a/libs/services/src/os/StatsDimensionsValue.cpp b/libs/services/src/os/StatsDimensionsValue.cpp deleted file mode 100644 index 0052e0baa905..000000000000 --- a/libs/services/src/os/StatsDimensionsValue.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#define LOG_TAG "StatsDimensionsValue" - -#include "android/os/StatsDimensionsValue.h" - -#include <cutils/log.h> - -using android::Parcel; -using android::Parcelable; -using android::status_t; -using std::vector; - -namespace android { -namespace os { - -StatsDimensionsValue::StatsDimensionsValue() {}; - -StatsDimensionsValue::StatsDimensionsValue(int32_t field, String16 value) : - mField(field), - mValueType(kStrValueType), - mStrValue(value) { -} -StatsDimensionsValue::StatsDimensionsValue(int32_t field, int32_t value) : - mField(field), - mValueType(kIntValueType), - mIntValue(value) { -} -StatsDimensionsValue::StatsDimensionsValue(int32_t field, int64_t value) : - mField(field), - mValueType(kLongValueType), - mLongValue(value) { -} -StatsDimensionsValue::StatsDimensionsValue(int32_t field, bool value) : - mField(field), - mValueType(kBoolValueType), - mBoolValue(value) { -} -StatsDimensionsValue::StatsDimensionsValue(int32_t field, float value) : - mField(field), - mValueType(kFloatValueType), - mFloatValue(value) { -} -StatsDimensionsValue::StatsDimensionsValue(int32_t field, vector<StatsDimensionsValue> value) : - mField(field), - mValueType(kTupleValueType), - mTupleValue(value) { -} - -StatsDimensionsValue::~StatsDimensionsValue() {} - -status_t -StatsDimensionsValue::writeToParcel(Parcel* out) const { - status_t err ; - - err = out->writeInt32(mField); - if (err != NO_ERROR) { - return err; - } - err = out->writeInt32(mValueType); - if (err != NO_ERROR) { - return err; - } - switch (mValueType) { - case kStrValueType: - err = out->writeString16(mStrValue); - break; - case kIntValueType: - err = out->writeInt32(mIntValue); - break; - case kLongValueType: - err = out->writeInt64(mLongValue); - break; - case kBoolValueType: - err = out->writeBool(mBoolValue); - break; - case kFloatValueType: - err = out->writeFloat(mFloatValue); - break; - case kTupleValueType: - { - int sz = mTupleValue.size(); - err = out->writeInt32(sz); - if (err != NO_ERROR) { - return err; - } - for (int i = 0; i < sz; ++i) { - err = mTupleValue[i].writeToParcel(out); - if (err != NO_ERROR) { - return err; - } - } - } - break; - default: - err = UNKNOWN_ERROR; - break; - } - return err; -} - -status_t -StatsDimensionsValue::readFromParcel(const Parcel* in) -{ - // Implement me if desired. We don't currently use this. - ALOGE("Cannot do c++ StatsDimensionsValue.readFromParcel(); it is not implemented."); - (void)in; // To prevent compile error of unused parameter 'in' - return UNKNOWN_ERROR; -} - -} // namespace os -} // namespace android diff --git a/core/java/android/os/StatsDimensionsValue.aidl b/location/java/android/location/GnssRequest.aidl index 81a14a4b67d9..581abcce6651 100644 --- a/core/java/android/os/StatsDimensionsValue.aidl +++ b/location/java/android/location/GnssRequest.aidl @@ -1,5 +1,5 @@ -/** - * Copyright (c) 2018, The Android Open Source Project +/* + * Copyright (C) 2020, 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -package android.os; +package android.location; -/** @hide */ -parcelable StatsDimensionsValue cpp_header "android/os/StatsDimensionsValue.h";
\ No newline at end of file +/** + * @hide + */ +parcelable GnssRequest; diff --git a/location/java/android/location/GnssRequest.java b/location/java/android/location/GnssRequest.java new file mode 100644 index 000000000000..2afb265f638c --- /dev/null +++ b/location/java/android/location/GnssRequest.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2020 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.location; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class contains extra parameters to pass to a GNSS provider implementation. + * @hide + */ +@SystemApi +public final class GnssRequest implements Parcelable { + private final boolean mFullTracking; + + /** + * Creates a {@link GnssRequest} with a full list of parameters. + */ + private GnssRequest(boolean fullTracking) { + mFullTracking = fullTracking; + } + + /** + * Represents whether to enable full GNSS tracking. + * + * <p>If true, GNSS chipset switches off duty cycling. In such a mode, no clock + * discontinuities are expected, and when supported, carrier phase should be continuous in + * good signal conditions. All non-blacklisted, healthy constellations, satellites and + * frequency bands that the chipset supports must be reported in this mode. The GNSS chipset + * is allowed to consume more power in this mode. If false, GNSS chipset optimizes power via + * duty cycling, constellations and frequency limits, etc. + */ + public boolean isFullTracking() { + return mFullTracking; + } + + @NonNull + public static final Creator<GnssRequest> CREATOR = + new Creator<GnssRequest>() { + @Override + @NonNull + public GnssRequest createFromParcel(@NonNull Parcel parcel) { + return new GnssRequest(parcel.readBoolean()); + } + + @Override + public GnssRequest[] newArray(int i) { + return new GnssRequest[i]; + } + }; + + @NonNull + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append("GnssRequest["); + s.append("FullTracking=").append(mFullTracking); + s.append(']'); + return s.toString(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof GnssRequest)) return false; + + GnssRequest other = (GnssRequest) obj; + if (mFullTracking != other.mFullTracking) return false; + + return true; + } + + @Override + public int hashCode() { + return mFullTracking ? 1 : 0; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeBoolean(mFullTracking); + } + + /** Builder for {@link GnssRequest} */ + public static final class Builder { + private boolean mFullTracking; + + /** + * Constructs a {@link Builder} instance. + */ + public Builder() { + } + + /** + * Constructs a {@link Builder} instance by copying a {@link GnssRequest}. + */ + public Builder(@NonNull GnssRequest request) { + mFullTracking = request.isFullTracking(); + } + + /** + * Set the value of whether to enable full GNSS tracking, which is false by default. + * + * <p>If true, GNSS chipset switches off duty cycling. In such a mode, no clock + * discontinuities are expected, and when supported, carrier phase should be continuous in + * good signal conditions. All non-blacklisted, healthy constellations, satellites and + * frequency bands that the chipset supports must be reported in this mode. The GNSS chipset + * is allowed to consume more power in this mode. If false, GNSS chipset optimizes power via + * duty cycling, constellations and frequency limits, etc. + * + * <p>Full tracking requests always override non-full tracking requests. If any full + * tracking request occurs, all listeners on the device will receive full tracking GNSS + * measurements. + */ + @NonNull public Builder setFullTracking(boolean value) { + mFullTracking = value; + return this; + } + + /** Builds a {@link GnssRequest} instance as specified by this builder. */ + @NonNull + public GnssRequest build() { + return new GnssRequest(mFullTracking); + } + } +} diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 1c10edb11293..7e6486cc933e 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -2196,6 +2196,30 @@ public class LocationManager { } /** + * Registers a GNSS Measurement callback. + * + * @param request extra parameters to pass to GNSS measurement provider. For example, if {@link + * GnssRequest#isFullTrackingEnabled()} is true, GNSS chipset switches off duty + * cycling. + * @param executor the executor that the callback runs on. + * @param callback a {@link GnssMeasurementsEvent.Callback} object to register. + * @return {@code true} if the callback was added successfully, {@code false} otherwise. + * @throws IllegalArgumentException if request is null + * @throws IllegalArgumentException if executor is null + * @throws IllegalArgumentException if callback is null + * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present + * @hide + */ + @SystemApi + @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, LOCATION_HARDWARE}) + public boolean registerGnssMeasurementsCallback( + @NonNull GnssRequest request, + @NonNull @CallbackExecutor Executor executor, + @NonNull GnssMeasurementsEvent.Callback callback) { + throw new RuntimeException(); + } + + /** * Injects GNSS measurement corrections into the GNSS chipset. * * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java index c1b17d3615bb..63de03344219 100644 --- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java +++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java @@ -41,8 +41,7 @@ public class FrontendStatus { FRONTEND_STATUS_TYPE_MODULATION, FRONTEND_STATUS_TYPE_SPECTRAL, FRONTEND_STATUS_TYPE_LNB_VOLTAGE, FRONTEND_STATUS_TYPE_PLP_ID, FRONTEND_STATUS_TYPE_EWBS, FRONTEND_STATUS_TYPE_AGC, FRONTEND_STATUS_TYPE_LNA, - FRONTEND_STATUS_TYPE_LAYER_ERROR, FRONTEND_STATUS_TYPE_VBER_CN, - FRONTEND_STATUS_TYPE_LBER_CN, FRONTEND_STATUS_TYPE_XER_CN, FRONTEND_STATUS_TYPE_MER, + FRONTEND_STATUS_TYPE_LAYER_ERROR, FRONTEND_STATUS_TYPE_MER, FRONTEND_STATUS_TYPE_FREQ_OFFSET, FRONTEND_STATUS_TYPE_HIERARCHY, FRONTEND_STATUS_TYPE_RF_LOCK, FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO}) @Retention(RetentionPolicy.SOURCE) @@ -125,18 +124,6 @@ public class FrontendStatus { public static final int FRONTEND_STATUS_TYPE_LAYER_ERROR = Constants.FrontendStatusType.LAYER_ERROR; /** - * CN value by VBER. - */ - public static final int FRONTEND_STATUS_TYPE_VBER_CN = Constants.FrontendStatusType.VBER_CN; - /** - * CN value by LBER. - */ - public static final int FRONTEND_STATUS_TYPE_LBER_CN = Constants.FrontendStatusType.LBER_CN; - /** - * CN value by XER. - */ - public static final int FRONTEND_STATUS_TYPE_XER_CN = Constants.FrontendStatusType.XER_CN; - /** * Modulation Error Ratio. */ public static final int FRONTEND_STATUS_TYPE_MER = Constants.FrontendStatusType.MER; @@ -223,9 +210,6 @@ public class FrontendStatus { private Integer mAgc; private Boolean mIsLnaOn; private boolean[] mIsLayerErrors; - private Integer mVberCn; - private Integer mLberCn; - private Integer mXerCn; private Integer mMer; private Integer mFreqOffset; private Integer mHierarchy; @@ -403,33 +387,6 @@ public class FrontendStatus { return mIsLayerErrors; } /** - * Gets CN value by VBER in thousandths of a deciBel (0.001dB). - */ - public int getVberCn() { - if (mVberCn == null) { - throw new IllegalStateException(); - } - return mVberCn; - } - /** - * Gets CN value by LBER in thousandths of a deciBel (0.001dB). - */ - public int getLberCn() { - if (mLberCn == null) { - throw new IllegalStateException(); - } - return mLberCn; - } - /** - * Gets CN value by XER in thousandths of a deciBel (0.001dB). - */ - public int getXerCn() { - if (mXerCn == null) { - throw new IllegalStateException(); - } - return mXerCn; - } - /** * Gets Modulation Error Ratio in thousandths of a deciBel (0.001dB). */ public int getMer() { diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java index f90144bc97ef..8105c74cfb62 100644 --- a/media/java/android/media/tv/tuner/frontend/ScanCallback.java +++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java @@ -67,7 +67,7 @@ public interface ScanCallback { /** Frontend hierarchy. */ void onHierarchy(@DvbtFrontendSettings.Hierarchy int hierarchy); - /** Frontend hierarchy. */ + /** Frontend signal type. */ void onSignalType(@AnalogFrontendSettings.SignalType int signalType); } diff --git a/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml b/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml index a06dc546f85c..c4d8f35cec71 100644 --- a/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml +++ b/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml @@ -29,7 +29,7 @@ <service android:enabled="true" android:name="com.android.incremental.nativeadb.NativeAdbDataLoaderService" android:label="@string/app_name" - android:exported="true"> + android:exported="false"> <intent-filter> <action android:name="android.intent.action.LOAD_DATA" /> </intent-filter> diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 48d405a4b91f..18145939c384 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -97,6 +97,7 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -193,9 +194,7 @@ public class BugreportProgressService extends Service { * <p> * Must be a path supported by its FileProvider. */ - // TODO: use the same variable for both dir - private static final String SCREENSHOT_DIR = "bugreports"; - private static final String BUGREPORT_DIR = "/bugreports"; + private static final String BUGREPORT_DIR = "bugreports"; private static final String NOTIFICATION_CHANNEL_ID = "bugreports"; @@ -230,7 +229,7 @@ public class BugreportProgressService extends Service { private final BugreportInfoDialog mInfoDialog = new BugreportInfoDialog(); - private File mScreenshotsDir; + private File mBugreportsDir; private BugreportManager mBugreportManager; @@ -263,11 +262,12 @@ public class BugreportProgressService extends Service { mScreenshotHandler = new ScreenshotHandler("BugreportProgressServiceScreenshotThread"); startSelfIntent = new Intent(this, this.getClass()); - mScreenshotsDir = new File(getFilesDir(), SCREENSHOT_DIR); - if (!mScreenshotsDir.exists()) { - Log.i(TAG, "Creating directory " + mScreenshotsDir + " to store temporary screenshots"); - if (!mScreenshotsDir.mkdir()) { - Log.w(TAG, "Could not create directory " + mScreenshotsDir); + mBugreportsDir = new File(getFilesDir(), BUGREPORT_DIR); + if (!mBugreportsDir.exists()) { + Log.i(TAG, "Creating directory " + mBugreportsDir + + " to store bugreports and screenshots"); + if (!mBugreportsDir.mkdir()) { + Log.w(TAG, "Could not create directory " + mBugreportsDir); } } final Configuration conf = mContext.getResources().getConfiguration(); @@ -372,7 +372,7 @@ public class BugreportProgressService extends Service { @Override public void onFinished() { mInfo.renameBugreportFile(); - mInfo.renameScreenshots(mScreenshotsDir); + mInfo.renameScreenshots(); synchronized (mLock) { sendBugreportFinishedBroadcastLocked(); } @@ -406,7 +406,7 @@ public class BugreportProgressService extends Service { mInfo.bugreportFile); } else { trackInfoWithIdLocked(); - cleanupOldFiles(MIN_KEEP_COUNT, MIN_KEEP_AGE); + cleanupOldFiles(MIN_KEEP_COUNT, MIN_KEEP_AGE, mBugreportsDir); final Intent intent = new Intent(INTENT_BUGREPORT_FINISHED); intent.putExtra(EXTRA_BUGREPORT, bugreportFilePath); intent.putExtra(EXTRA_SCREENSHOT, getScreenshotForIntent(mInfo)); @@ -418,7 +418,8 @@ public class BugreportProgressService extends Service { private static void sendRemoteBugreportFinishedBroadcast(Context context, String bugreportFileName, File bugreportFile) { - cleanupOldFiles(REMOTE_BUGREPORT_FILES_AMOUNT, REMOTE_MIN_KEEP_AGE); + cleanupOldFiles(REMOTE_BUGREPORT_FILES_AMOUNT, REMOTE_MIN_KEEP_AGE, + bugreportFile.getParentFile()); final Intent intent = new Intent(DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH); final Uri bugreportUri = getUri(context, bugreportFile); final String bugreportHash = generateFileHash(bugreportFileName); @@ -468,12 +469,12 @@ public class BugreportProgressService extends Service { return fileHash; } - static void cleanupOldFiles(final int minCount, final long minAge) { + static void cleanupOldFiles(final int minCount, final long minAge, File bugreportsDir) { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { try { - FileUtils.deleteOlderFiles(new File(BUGREPORT_DIR), minCount, minAge); + FileUtils.deleteOlderFiles(bugreportsDir, minCount, minAge); } catch (RuntimeException e) { Log.e(TAG, "RuntimeException deleting old files", e); } @@ -604,18 +605,25 @@ public class BugreportProgressService extends Service { String name = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); BugreportInfo info = new BugreportInfo(mContext, baseName, name, - shareTitle, shareDescription, bugreportType); + shareTitle, shareDescription, bugreportType, mBugreportsDir); + ParcelFileDescriptor bugreportFd; + ParcelFileDescriptor screenshotFd; - ParcelFileDescriptor bugreportFd = info.createBugreportFd(); - if (bugreportFd == null) { - Log.e(TAG, "Bugreport parcel file descriptor is null."); - return; - } - ParcelFileDescriptor screenshotFd = info.createScreenshotFd(); - if (screenshotFd == null) { - Log.e(TAG, "Screenshot parcel file descriptor is null. Deleting bugreport file"); - FileUtils.closeQuietly(bugreportFd); - info.bugreportFile.delete(); + try { + bugreportFd = info.createAndGetBugreportFd(); + if (bugreportFd == null) { + Log.e(TAG, "Bugreport parcel file descriptor is null."); + return; + } + screenshotFd = info.createAndGetDefaultScreenshotFd(); + if (screenshotFd == null) { + Log.e(TAG, "Screenshot parcel file descriptor is null. Deleting bugreport file"); + FileUtils.closeQuietly(bugreportFd); + info.bugreportFile.delete(); + return; + } + } catch (IOException e) { + Log.e(TAG, "Error in generating bugreport files: ", e); return; } mBugreportManager = (BugreportManager) mContext.getSystemService( @@ -639,21 +647,24 @@ public class BugreportProgressService extends Service { } } - private static ParcelFileDescriptor createReadWriteFile(File file) { + private static ParcelFileDescriptor getFd(File file) { try { - file.createNewFile(); - file.setReadable(true, true); - file.setWritable(true, true); - - ParcelFileDescriptor fd = ParcelFileDescriptor.open(file, + return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_APPEND); - return fd; - } catch (IOException e) { + } catch (FileNotFoundException e) { Log.i(TAG, "Error in generating bugreports: ", e); } return null; } + private static void createReadWriteFile(File file) throws IOException { + if (!file.exists()) { + file.createNewFile(); + file.setReadable(true, true); + file.setWritable(true, true); + } + } + /** * Updates the system notification for a given bugreport. */ @@ -874,7 +885,7 @@ public class BugreportProgressService extends Service { return; } final String screenshotPath = - new File(mScreenshotsDir, info.getPathNextScreenshot()).getAbsolutePath(); + new File(mBugreportsDir, info.getPathNextScreenshot()).getAbsolutePath(); Message.obtain(mScreenshotHandler, MSG_SCREENSHOT_REQUEST, id, UNUSED_ARG2, screenshotPath) .sendToTarget(); @@ -921,7 +932,7 @@ public class BugreportProgressService extends Service { info.addScreenshot(screenshotFile); if (info.finished) { Log.d(TAG, "Screenshot finished after bugreport; updating share notification"); - info.renameScreenshots(mScreenshotsDir); + info.renameScreenshots(); sendBugreportNotification(info, mTakingScreenshot); } msg = mContext.getString(R.string.bugreport_screenshot_taken); @@ -1030,11 +1041,10 @@ public class BugreportProgressService extends Service { /** * Build {@link Intent} that can be used to share the given bugreport. */ - private static Intent buildSendIntent(Context context, BugreportInfo info, - File screenshotsDir) { + private static Intent buildSendIntent(Context context, BugreportInfo info) { // Rename files (if required) before sharing info.renameBugreportFile(); - info.renameScreenshots(screenshotsDir); + info.renameScreenshots(); // Files are kept on private storage, so turn into Uris that we can // grant temporary permissions for. final Uri bugreportUri; @@ -1120,7 +1130,7 @@ public class BugreportProgressService extends Service { addDetailsToZipFile(info); - final Intent sendIntent = buildSendIntent(mContext, info, mScreenshotsDir); + final Intent sendIntent = buildSendIntent(mContext, info); if (sendIntent == null) { Log.w(TAG, "Stopping progres on ID " + id + " because share intent could not be built"); synchronized (mLock) { @@ -1813,24 +1823,37 @@ public class BugreportProgressService extends Service { */ BugreportInfo(Context context, String baseName, String name, @Nullable String shareTitle, @Nullable String shareDescription, - @BugreportParams.BugreportMode int type) { + @BugreportParams.BugreportMode int type, File bugreportsDir) { this.context = context; this.name = this.initialName = name; this.shareTitle = shareTitle == null ? "" : shareTitle; this.shareDescription = shareDescription == null ? "" : shareDescription; this.type = type; this.baseName = baseName; + createBugreportFile(bugreportsDir); + createScreenshotFile(bugreportsDir); } - ParcelFileDescriptor createBugreportFd() { - bugreportFile = new File(BUGREPORT_DIR, getFileName(this, ".zip")); - return createReadWriteFile(bugreportFile); + void createBugreportFile(File bugreportsDir) { + bugreportFile = new File(bugreportsDir, getFileName(this, ".zip")); } - ParcelFileDescriptor createScreenshotFd() { - File screenshotFile = new File(BUGREPORT_DIR, getScreenshotName("default")); + void createScreenshotFile(File bugreportsDir) { + File screenshotFile = new File(bugreportsDir, getScreenshotName("default")); addScreenshot(screenshotFile); - return createReadWriteFile(screenshotFile); + } + + ParcelFileDescriptor createAndGetBugreportFd() throws IOException { + createReadWriteFile(bugreportFile); + return getFd(bugreportFile); + } + + ParcelFileDescriptor createAndGetDefaultScreenshotFd() throws IOException { + if (screenshotFiles.isEmpty()) { + return null; + } + createReadWriteFile(screenshotFiles.get(0)); + return getFd(screenshotFiles.get(0)); } /** @@ -1859,7 +1882,7 @@ public class BugreportProgressService extends Service { * Rename all screenshots files so that they contain the new {@code name} instead of the * {@code initialName} if user has changed it. */ - void renameScreenshots(File screenshotDir) { + void renameScreenshots() { if (TextUtils.isEmpty(name)) { return; } @@ -1869,7 +1892,7 @@ public class BugreportProgressService extends Service { final String newName = oldName.replaceFirst(initialName, name); final File newFile; if (!newName.equals(oldName)) { - final File renamedFile = new File(screenshotDir, newName); + final File renamedFile = new File(oldFile.getParentFile(), newName); Log.d(TAG, "Renaming screenshot file " + oldFile + " to " + renamedFile); newFile = oldFile.renameTo(renamedFile) ? renamedFile : oldFile; } else { @@ -1889,7 +1912,8 @@ public class BugreportProgressService extends Service { * Rename bugreport file to include the name given by user via UI */ void renameBugreportFile() { - File newBugreportFile = new File(BUGREPORT_DIR, getFileName(this, ".zip")); + File newBugreportFile = new File(bugreportFile.getParentFile(), + getFileName(this, ".zip")); if (!newBugreportFile.getPath().equals(bugreportFile.getPath())) { if (bugreportFile.renameTo(newBugreportFile)) { bugreportFile = newBugreportFile; diff --git a/packages/SystemUI/res/drawable-nodpi/android_11_dial.xml b/packages/SystemUI/res/drawable-nodpi/android_11_dial.xml new file mode 100644 index 000000000000..73fd37f1bdd6 --- /dev/null +++ b/packages/SystemUI/res/drawable-nodpi/android_11_dial.xml @@ -0,0 +1,63 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + <path + android:pathData="M77.773,51.064h-1.583c-0.217,0 -0.393,-0.176 -0.393,-0.393v-1.46c0,-0.217 0.176,-0.393 0.393,-0.393h3.466c0.217,0 0.393,0.176 0.393,0.393v9.921c0,0.217 -0.176,0.393 -0.393,0.393h-1.49c-0.217,0 -0.393,-0.176 -0.393,-0.393V51.064z" + android:fillColor="#F86734"/> + <path + android:pathData="M83.598,51.064h-1.583c-0.217,0 -0.393,-0.176 -0.393,-0.393v-1.46c0,-0.217 0.176,-0.393 0.393,-0.393h3.466c0.217,0 0.393,0.176 0.393,0.393v9.921c0,0.217 -0.176,0.393 -0.393,0.393h-1.49c-0.217,0 -0.393,-0.176 -0.393,-0.393V51.064z" + android:fillColor="#F86734"/> + <path + android:pathData="M70.044,75.974m-0.644,0a0.644,0.644 0,1 1,1.288 0a0.644,0.644 0,1 1,-1.288 0" + android:fillColor="#d7effe"/> + <path + android:pathData="M56.896,80.985m-0.718,0a0.718,0.718 0,1 1,1.436 0a0.718,0.718 0,1 1,-1.436 0" + android:fillColor="#d7effe"/> + <path + android:pathData="M43.408,78.881m-0.795,0a0.795,0.795 0,1 1,1.59 0a0.795,0.795 0,1 1,-1.59 0" + android:fillColor="#d7effe"/> + <path + android:pathData="M32.419,70.115m-0.874,0a0.874,0.874 0,1 1,1.748 0a0.874,0.874 0,1 1,-1.748 0" + android:fillColor="#d7effe"/> + <path + android:pathData="M27.306,56.992m-0.954,0a0.954,0.954 0,1 1,1.908 0a0.954,0.954 0,1 1,-1.908 0" + android:fillColor="#d7effe"/> + <path + android:pathData="M29.313,43.489m-1.036,0a1.036,1.036 0,1 1,2.072 0a1.036,1.036 0,1 1,-2.072 0" + android:fillColor="#d7effe"/> + <path + android:pathData="M37.988,32.445m-1.118,0a1.118,1.118 0,1 1,2.236 0a1.118,1.118 0,1 1,-2.236 0" + android:fillColor="#d7effe"/> + <path + android:pathData="M51.137,27.064m-1.201,0a1.201,1.201 0,1 1,2.402 0a1.201,1.201 0,1 1,-2.402 0" + android:fillColor="#d7effe"/> + <path + android:pathData="M64.553,28.868m-1.284,0a1.284,1.284 0,1 1,2.568 0a1.284,1.284 0,1 1,-2.568 0" + android:fillColor="#d7effe"/> + <path + android:pathData="M75.522,37.652m-1.368,0a1.368,1.368 0,1 1,2.736 0a1.368,1.368 0,1 1,-2.736 0" + android:fillColor="#d7effe"/> + <path + android:pathData="M87.942,115.052l-47.557,-47.557l26.869,-26.87l47.557,47.558z"> + <aapt:attr name="android:fillColor"> + <gradient + android:startY="56.087" + android:startX="55.8464" + android:endY="100.0297" + android:endX="99.7891" + android:type="linear"> + <item android:offset="0" android:color="#3F000000"/> + <item android:offset="1" android:color="#00000000"/> + </gradient> + </aapt:attr> + </path> + <path + android:pathData="M53.928,54.17m-18.999,0a18.999,18.999 0,1 1,37.998 0a18.999,18.999 0,1 1,-37.998 0" + android:fillColor="#3ddc84"/> + <path + android:pathData="M66.353,54.17m-3.185,0a3.185,3.185 0,1 1,6.37 0a3.185,3.185 0,1 1,-6.37 0" + android:fillColor="#FFFFFF"/> +</vector> diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml index 7a68c032d8be..7f8d4fa8833f 100644 --- a/packages/SystemUI/res/drawable-nodpi/icon.xml +++ b/packages/SystemUI/res/drawable-nodpi/icon.xml @@ -15,5 +15,5 @@ Copyright (C) 2018 The Android Open Source Project --> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <background android:drawable="@drawable/icon_bg"/> - <foreground android:drawable="@drawable/q"/> + <foreground android:drawable="@drawable/android_11_dial"/> </adaptive-icon> diff --git a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml index 2a54dfad8191..31b2a7f9a333 100644 --- a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml +++ b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml @@ -14,5 +14,5 @@ Copyright (C) 2018 The Android Open Source Project limitations under the License. --> <color xmlns:android="http://schemas.android.com/apk/res/android" - android:color="#77C360" /> + android:color="#073042" /> diff --git a/packages/SystemUI/res/drawable-nodpi/q.xml b/packages/SystemUI/res/drawable-nodpi/q.xml deleted file mode 100644 index 0f42d2e20040..000000000000 --- a/packages/SystemUI/res/drawable-nodpi/q.xml +++ /dev/null @@ -1,40 +0,0 @@ -<!-- -Copyright (C) 2019 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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="108dp" - android:height="108dp" - android:viewportWidth="108.0" - android:viewportHeight="108.0"> - <group - android:name="scale" - android:pivotX="54" android:pivotY="54" - android:scaleX="0.9" - android:scaleY="0.9"> - <group - android:name="nudge" - android:translateX="24" - android:translateY="23.5"> - <path - android:name="tail" - android:fillColor="#FFFFFF" - android:pathData="M21.749674,34.122784l-9.431964,9.529709l-6.31771,-6.2529106l15.736504,-15.899582l64.765724,65.16436l-6.3046494,6.266083z"/> - <path - android:name="counter" - android:fillColor="#FFFFFF" - android:pathData="M30,9.32352941 C41.6954418,9.32352941 51.1764706,18.8045582 51.1764706,30.5 C51.1764706,42.1954418 41.6954418,51.6764706 30,51.6764706 C18.3045582,51.6764706 8.82352941,42.1954418 8.82352941,30.5 C8.82352941,18.8045582 18.3045582,9.32352941 30,9.32352941 L30,9.32352941 Z M30,0.5 C13.4314575,0.5 -5.53805368e-15,13.9314575 -7.10542736e-15,30.5 C-1.02401747e-14,47.0685425 13.4314575,60.5 30,60.5 C46.5685425,60.5 60,47.0685425 60,30.5 C59.9805514,13.9395201 46.5604799,0.519448617 30,0.5 Z"/> - </group> - </group> -</vector> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index c4fa4e5d4ef3..7a3395c229a0 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1090,7 +1090,7 @@ <!-- Blur radius on status bar window and power menu --> <dimen name="min_window_blur_radius">1px</dimen> - <dimen name="max_window_blur_radius">250px</dimen> + <dimen name="max_window_blur_radius">150px</dimen> <!-- How much into a DisplayCutout's bounds we can go, on each side --> <dimen name="display_cutout_margin_consumption">0px</dimen> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index f61f585cfe7c..f48210cf90c4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -42,7 +42,6 @@ import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.animation.Animation; -import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; @@ -251,9 +250,9 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe SliceItem item = rc.getSliceItem(); final Uri itemTag = item.getSlice().getUri(); // Try to reuse the view if already exists in the layout - KeyguardSliceButton button = mRow.findViewWithTag(itemTag); + KeyguardSliceTextView button = mRow.findViewWithTag(itemTag); if (button == null) { - button = new KeyguardSliceButton(mContext); + button = new KeyguardSliceTextView(mContext); button.setTextColor(blendedColor); button.setTag(itemTag); final int viewIndex = i - (mHasHeader ? 1 : 0); @@ -316,8 +315,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe int childCount = mRow.getChildCount(); for (int i = 0; i < childCount; i++) { View v = mRow.getChildAt(i); - if (v instanceof Button) { - ((Button) v).setTextColor(blendedColor); + if (v instanceof TextView) { + ((TextView) v).setTextColor(blendedColor); } } } @@ -500,8 +499,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); - if (child instanceof KeyguardSliceButton) { - ((KeyguardSliceButton) child).setMaxWidth(width / childCount); + if (child instanceof KeyguardSliceTextView) { + ((KeyguardSliceTextView) child).setMaxWidth(width / childCount); } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -527,13 +526,13 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe * Representation of an item that appears under the clock on main keyguard message. */ @VisibleForTesting - static class KeyguardSliceButton extends Button implements + static class KeyguardSliceTextView extends TextView implements ConfigurationController.ConfigurationListener { @StyleRes private static int sStyleId = R.style.TextAppearance_Keyguard_Secondary; - public KeyguardSliceButton(Context context) { + KeyguardSliceTextView(Context context) { super(context, null /* attrs */, 0 /* styleAttr */, sStyleId); onDensityOrFontScaleChanged(); setEllipsize(TruncateAt.END); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index 0ec739fecaa7..53a23b89f943 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -30,7 +30,6 @@ import android.view.IWindowManager; import android.view.LayoutInflater; import com.android.internal.logging.MetricsLogger; -import com.android.internal.util.NotificationMessagingUtil; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.dagger.qualifiers.Background; @@ -192,12 +191,6 @@ public class DependencyProvider { return new AlwaysOnDisplayPolicy(context); } - /***/ - @Provides - public NotificationMessagingUtil provideNotificationMessagingUtil(Context context) { - return new NotificationMessagingUtil(context); - } - /** */ @Provides public ViewMediatorCallback providesViewMediatorCallback(KeyguardViewMediator viewMediator) { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index f068d9c10e86..7b541991088c 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -40,7 +40,6 @@ import com.android.systemui.statusbar.notification.collection.inflation.Notifica import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.notification.people.PeopleHubModule; -import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; import com.android.systemui.statusbar.phone.KeyguardLiftController; import com.android.systemui.statusbar.phone.StatusBar; @@ -69,9 +68,7 @@ import dagger.Provides; NotificationsModule.class, PeopleHubModule.class, }, - subcomponents = {StatusBarComponent.class, - NotificationRowComponent.class, - ExpandableNotificationRowComponent.class}) + subcomponents = {StatusBarComponent.class, NotificationRowComponent.class}) public abstract class SystemUIModule { @Binds diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 14eec59211bd..9da99c453022 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -151,7 +151,7 @@ public class KeyguardViewMediator extends SystemUI { private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000; private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000; - private static final boolean DEBUG = KeyguardConstants.DEBUG; + private static final boolean DEBUG = true; private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES; private final static String TAG = "KeyguardViewMediator"; diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index 411980b399bd..ae6162219afa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -83,7 +83,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener mTile = new Tile(); updateDefaultTileAndIcon(); mServiceManager = host.getTileServices().getTileWrapper(this); - if (mServiceManager.isBooleanTile()) { + if (mServiceManager.isToggleableTile()) { // Replace states with BooleanState resetStates(); } @@ -252,7 +252,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener @Override public State newTileState() { - if (mServiceManager != null && mServiceManager.isBooleanTile()) { + if (mServiceManager != null && mServiceManager.isToggleableTile()) { return new BooleanState(); } return new State(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java index ad79cadcc12d..17b0251837e7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java @@ -141,16 +141,16 @@ public class TileLifecycleManager extends BroadcastReceiver implements /** * Determines whether the associated TileService is a Boolean Tile. * - * @return true if {@link TileService#META_DATA_BOOLEAN_TILE} is set to {@code true} for this + * @return true if {@link TileService#META_DATA_TOGGLEABLE_TILE} is set to {@code true} for this * tile - * @see TileService#META_DATA_BOOLEAN_TILE + * @see TileService#META_DATA_TOGGLEABLE_TILE */ - public boolean isBooleanTile() { + public boolean isToggleableTile() { try { ServiceInfo info = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(), PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA); return info.metaData != null - && info.metaData.getBoolean(TileService.META_DATA_BOOLEAN_TILE, false); + && info.metaData.getBoolean(TileService.META_DATA_TOGGLEABLE_TILE, false); } catch (PackageManager.NameNotFoundException e) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java index 1902d655abc3..cfa8fb6373a1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java @@ -124,8 +124,8 @@ public class TileServiceManager { return mStateManager.isActiveTile(); } - public boolean isBooleanTile() { - return mStateManager.isBooleanTile(); + public boolean isToggleableTile() { + return mStateManager.isToggleableTile(); } public void setShowingDialog(boolean dialog) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 006d40ddbac5..41c1b7b5fae8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -69,7 +69,6 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; import com.android.systemui.statusbar.notification.row.NotificationGuts; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager; @@ -154,7 +153,6 @@ public final class NotificationEntry extends ListEntry { private NotificationEntry parent; // our parent (if we're in a group) private ExpandableNotificationRow row; // the outer expanded view - private ExpandableNotificationRowController mRowController; private int mCachedContrastColor = COLOR_INVALID; private int mCachedContrastColorIsFor = COLOR_INVALID; @@ -426,14 +424,6 @@ public final class NotificationEntry extends ListEntry { this.row = row; } - public ExpandableNotificationRowController getRowController() { - return mRowController; - } - - public void setRowController(ExpandableNotificationRowController controller) { - mRowController = controller; - } - @Nullable public List<NotificationEntry> getChildren() { if (row == null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java index e8a62e48e75e..ecf62db4680b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.collection.inflation; import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; +import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; import android.annotation.Nullable; @@ -39,19 +40,19 @@ import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.NotificationClicker; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; import com.android.systemui.statusbar.notification.row.NotifBindPipeline; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder; import com.android.systemui.statusbar.notification.row.RowContentBindParams; import com.android.systemui.statusbar.notification.row.RowContentBindStage; import com.android.systemui.statusbar.notification.row.RowInflaterTask; -import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.HeadsUpManager; import java.util.Objects; @@ -66,28 +67,35 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { private static final String TAG = "NotificationViewManager"; + private final NotificationGroupManager mGroupManager; + private final NotificationGutsManager mGutsManager; private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; private final Context mContext; private final NotifBindPipeline mNotifBindPipeline; private final RowContentBindStage mRowContentBindStage; private final NotificationMessagingUtil mMessagingUtil; + private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger = + this::logNotificationExpansion; private final NotificationRemoteInputManager mNotificationRemoteInputManager; private final NotificationLockscreenUserManager mNotificationLockscreenUserManager; + private final boolean mAllowLongPress; + private final KeyguardBypassController mKeyguardBypassController; + private final StatusBarStateController mStatusBarStateController; private NotificationPresenter mPresenter; private NotificationListContainer mListContainer; + private HeadsUpManager mHeadsUpManager; private NotificationRowContentBinder.InflationCallback mInflationCallback; + private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener; private BindRowCallback mBindRowCallback; private NotificationClicker mNotificationClicker; private final Provider<RowInflaterTask> mRowInflaterTaskProvider; - private final ExpandableNotificationRowComponent.Builder - mExpandableNotificationRowComponentBuilder; + private final NotificationLogger mNotificationLogger; @Inject public NotificationRowBinderImpl( Context context, - NotificationMessagingUtil notificationMessagingUtil, NotificationRemoteInputManager notificationRemoteInputManager, NotificationLockscreenUserManager notificationLockscreenUserManager, NotifBindPipeline notifBindPipeline, @@ -99,16 +107,21 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { NotificationGutsManager notificationGutsManager, NotificationInterruptionStateProvider notificationInterruptionStateProvider, Provider<RowInflaterTask> rowInflaterTaskProvider, - ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder) { + NotificationLogger logger) { mContext = context; mNotifBindPipeline = notifBindPipeline; mRowContentBindStage = rowContentBindStage; - mMessagingUtil = notificationMessagingUtil; + mMessagingUtil = new NotificationMessagingUtil(context); mNotificationRemoteInputManager = notificationRemoteInputManager; mNotificationLockscreenUserManager = notificationLockscreenUserManager; + mAllowLongPress = allowLongPress; + mKeyguardBypassController = keyguardBypassController; + mStatusBarStateController = statusBarStateController; + mGroupManager = notificationGroupManager; + mGutsManager = notificationGutsManager; mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; mRowInflaterTaskProvider = rowInflaterTaskProvider; - mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder; + mNotificationLogger = logger; } /** @@ -116,10 +129,13 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { */ public void setUpWithPresenter(NotificationPresenter presenter, NotificationListContainer listContainer, + HeadsUpManager headsUpManager, BindRowCallback bindRowCallback) { mPresenter = presenter; mListContainer = listContainer; + mHeadsUpManager = headsUpManager; mBindRowCallback = bindRowCallback; + mOnAppOpsClickListener = mGutsManager::openGuts; } public void setInflationCallback(NotificationRowContentBinder.InflationCallback callback) { @@ -134,7 +150,9 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { * Inflates the views for the given entry (possibly asynchronously). */ @Override - public void inflateViews(NotificationEntry entry, Runnable onDismissRunnable) + public void inflateViews( + NotificationEntry entry, + Runnable onDismissRunnable) throws InflationException { ViewGroup parent = mListContainer.getViewParentForNotification(entry); PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext, @@ -145,26 +163,12 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { entry.updateIcons(mContext, sbn); entry.reset(); updateNotification(entry, pmUser, sbn, entry.getRow()); - entry.getRowController().setOnDismissRunnable(onDismissRunnable); + entry.getRow().setOnDismissRunnable(onDismissRunnable); } else { entry.createIcons(mContext, sbn); mRowInflaterTaskProvider.get().inflate(mContext, parent, entry, row -> { - // Setup the controller for the view. - ExpandableNotificationRowComponent component = - mExpandableNotificationRowComponentBuilder - .expandableNotificationRow(row) - .notificationEntry(entry) - .onDismissRunnable(onDismissRunnable) - .inflationCallback(mInflationCallback) - .rowContentBindStage(mRowContentBindStage) - .onExpandClickListener(mPresenter) - .build(); - ExpandableNotificationRowController rowController = - component.getExpandableNotificationRowController(); - rowController.init(); - entry.setRowController(rowController); - bindRow(entry, pmUser, sbn, row); + bindRow(entry, pmUser, sbn, row, onDismissRunnable); updateNotification(entry, pmUser, sbn, row); }); } @@ -172,12 +176,55 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { //TODO: This method associates a row with an entry, but eventually needs to not do that private void bindRow(NotificationEntry entry, PackageManager pmUser, - StatusBarNotification sbn, ExpandableNotificationRow row) { + StatusBarNotification sbn, ExpandableNotificationRow row, + Runnable onDismissRunnable) { + // Get the app name. + // Note that Notification.Builder#bindHeaderAppName has similar logic + // but since this field is used in the guts, it must be accurate. + // Therefore we will only show the application label, or, failing that, the + // package name. No substitutions. + final String pkg = sbn.getPackageName(); + String appname = pkg; + try { + final ApplicationInfo info = pmUser.getApplicationInfo(pkg, + PackageManager.MATCH_UNINSTALLED_PACKAGES + | PackageManager.MATCH_DISABLED_COMPONENTS); + if (info != null) { + appname = String.valueOf(pmUser.getApplicationLabel(info)); + } + } catch (PackageManager.NameNotFoundException e) { + // Do nothing + } + + row.initialize( + appname, + sbn.getKey(), + mExpansionLogger, + mKeyguardBypassController, + mGroupManager, + mHeadsUpManager, + mRowContentBindStage, + mPresenter); + + // TODO: Either move these into ExpandableNotificationRow#initialize or out of row entirely + row.setStatusBarStateController(mStatusBarStateController); + row.setAppOpsOnClickListener(mOnAppOpsClickListener); + if (mAllowLongPress) { + row.setLongPressListener(mGutsManager::openGuts); + } mListContainer.bindRow(row); mNotificationRemoteInputManager.bindRow(row); + + row.setOnDismissRunnable(onDismissRunnable); + row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + if (ENABLE_REMOTE_INPUT) { + row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); + } + entry.setRow(row); row.setEntry(entry); mNotifBindPipeline.manageRow(entry, row); + mBindRowCallback.onBindRow(entry, pmUser, sbn, row); } @@ -260,6 +307,10 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { Objects.requireNonNull(mNotificationClicker).register(row, sbn); } + private void logNotificationExpansion(String key, boolean userAction, boolean expanded) { + mNotificationLogger.onExpansionChanged(key, userAction, expanded); + } + /** Callback for when a row is bound to an entry. */ public interface BindRowCallback { /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index 3e0bcbb796bf..254b64ffcd90 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -90,6 +90,7 @@ class NotificationsControllerImpl @Inject constructor( notificationRowBinder.setUpWithPresenter( presenter, listContainer, + headsUpManager, bindRowCallback) if (featureFlags.isNewNotifPipelineEnabled) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index a6ef81d4612c..50a20374fee5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -29,17 +29,20 @@ import android.util.MathUtils; import android.view.MotionEvent; import android.view.View; import android.view.ViewAnimationUtils; +import android.view.accessibility.AccessibilityManager; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; -import com.android.systemui.Gefingerpoken; +import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.notification.FakeShadowView; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import com.android.systemui.statusbar.phone.DoubleTapHelper; /** * Base class for both {@link ExpandableNotificationRow} and {@link NotificationShelf} @@ -91,12 +94,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR = new PathInterpolator(0, 0, 0.5f, 1); private int mTintedRippleColor; - private int mNormalRippleColor; - private Gefingerpoken mTouchHandler; + protected int mNormalRippleColor; + private final AccessibilityManager mAccessibilityManager; + private final DoubleTapHelper mDoubleTapHelper; private boolean mDimmed; - int mBgTint = NO_COLOR; + protected int mBgTint = NO_COLOR; + private float mBgAlpha = 1f; /** * Flag to indicate that the notification has been touched once and the second touch will @@ -111,7 +116,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private Interpolator mCurrentAppearInterpolator; private Interpolator mCurrentAlphaInterpolator; - NotificationBackgroundView mBackgroundNormal; + protected NotificationBackgroundView mBackgroundNormal; private NotificationBackgroundView mBackgroundDimmed; private ObjectAnimator mBackgroundAnimator; private RectF mAppearAnimationRect = new RectF(); @@ -125,6 +130,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private boolean mLastInSection; private boolean mFirstInSection; private boolean mIsBelowSpeedBump; + private final FalsingManager mFalsingManager; private float mNormalBackgroundVisibilityAmount; private float mDimmedBackgroundFadeInAmount = -1; @@ -148,24 +154,38 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView */ private boolean mNeedsDimming; private int mDimmedAlpha; + private boolean mBlockNextTouch; private boolean mIsHeadsUpAnimation; private int mHeadsUpAddStartLocation; private float mHeadsUpLocation; private boolean mIsAppearing; private boolean mDismissed; private boolean mRefocusOnDismiss; - private OnDimmedListener mOnDimmedListener; public ActivatableNotificationView(Context context, AttributeSet attrs) { super(context, attrs); mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f); mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f); + mFalsingManager = Dependency.get(FalsingManager.class); // TODO: inject into a controller. setClipChildren(false); setClipToPadding(false); updateColors(); + mAccessibilityManager = AccessibilityManager.getInstance(mContext); + + mDoubleTapHelper = new DoubleTapHelper(this, (active) -> { + if (active) { + makeActive(); + } else { + makeInactive(true /* animate */); + } + }, super::performClick, this::handleSlideBack, mFalsingManager::onNotificationDoubleTap); initDimens(); } + public FalsingManager getFalsingManager() { + return mFalsingManager; + } + private void updateColors() { mNormalColor = mContext.getColor(R.color.notification_material_background_color); mTintedRippleColor = mContext.getColor( @@ -216,15 +236,32 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim); } + private final Runnable mTapTimeoutRunnable = new Runnable() { + @Override + public void run() { + makeInactive(true /* animate */); + } + }; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - if (mTouchHandler != null && mTouchHandler.onInterceptTouchEvent(ev)) { - return true; + if (mNeedsDimming && ev.getActionMasked() == MotionEvent.ACTION_DOWN + && disallowSingleClick(ev) && !isTouchExplorationEnabled()) { + if (!mActivated) { + return true; + } else if (!mDoubleTapHelper.isWithinDoubleTapSlop(ev)) { + mBlockNextTouch = true; + makeInactive(true /* animate */); + return true; + } } return super.onInterceptTouchEvent(ev); } + private boolean isTouchExplorationEnabled() { + return mAccessibilityManager.isTouchExplorationEnabled(); + } + protected boolean disallowSingleClick(MotionEvent ev) { return false; } @@ -233,6 +270,25 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView return false; } + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean result; + if (mBlockNextTouch) { + mBlockNextTouch = false; + return false; + } + if (mNeedsDimming && !isTouchExplorationEnabled() && isInteractive()) { + boolean wasActivated = mActivated; + result = handleTouchEventDimmed(event); + if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) { + removeCallbacks(mTapTimeoutRunnable); + } + } else { + result = super.onTouchEvent(event); + } + return result; + } + /** * @return whether this view is interactive and can be double tapped */ @@ -257,11 +313,28 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } } - void setRippleAllowed(boolean allowed) { + public void setRippleAllowed(boolean allowed) { mBackgroundNormal.setPressedAllowed(allowed); } - void makeActive() { + private boolean handleTouchEventDimmed(MotionEvent event) { + if (mNeedsDimming && !mDimmed) { + // We're actually dimmed, but our content isn't dimmable, let's ensure we have a ripple + super.onTouchEvent(event); + } + return mDoubleTapHelper.onTouchEvent(event, getActualHeight()); + } + + @Override + public boolean performClick() { + if (!mNeedsDimming || isTouchExplorationEnabled()) { + return super.performClick(); + } + return false; + } + + private void makeActive() { + mFalsingManager.onNotificationActive(); startActivateAnimation(false /* reverse */); mActivated = true; if (mOnActivatedListener != null) { @@ -315,12 +388,15 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundNormal.animate() .alpha(reverse ? 0f : 1f) .setInterpolator(alphaInterpolator) - .setUpdateListener(animation -> { - float animatedFraction = animation.getAnimatedFraction(); - if (reverse) { - animatedFraction = 1.0f - animatedFraction; + .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animatedFraction = animation.getAnimatedFraction(); + if (reverse) { + animatedFraction = 1.0f - animatedFraction; + } + setNormalBackgroundVisibilityAmount(animatedFraction); } - setNormalBackgroundVisibilityAmount(animatedFraction); }) .setDuration(ACTIVATE_ANIMATION_LENGTH); } @@ -342,13 +418,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView if (mOnActivatedListener != null) { mOnActivatedListener.onActivationReset(this); } + removeCallbacks(mTapTimeoutRunnable); } public void setDimmed(boolean dimmed, boolean fade) { mNeedsDimming = dimmed; - if (mOnDimmedListener != null) { - mOnDimmedListener.onSetDimmed(dimmed); - } dimmed &= isDimmable(); if (mDimmed != dimmed) { mDimmed = dimmed; @@ -365,17 +439,13 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView return true; } - public boolean isDimmed() { - return mDimmed; - } - private void updateOutlineAlpha() { float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED; alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount); setOutlineAlpha(alpha); } - private void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) { + public void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) { mNormalBackgroundVisibilityAmount = normalBackgroundVisibilityAmount; updateOutlineAlpha(); } @@ -403,14 +473,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView /** * Sets the tint color of the background */ - protected void setTintColor(int color) { + public void setTintColor(int color) { setTintColor(color, false); } /** * Sets the tint color of the background */ - void setTintColor(int color, boolean animated) { + public void setTintColor(int color, boolean animated) { if (color != mBgTint) { mBgTint = color; updateBackgroundTint(animated); @@ -492,10 +562,13 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mStartTint = mCurrentBackgroundTint; mTargetTint = color; mBackgroundColorAnimator = ValueAnimator.ofFloat(0.0f, 1.0f); - mBackgroundColorAnimator.addUpdateListener(animation -> { - int newColor = NotificationUtils.interpolateColors(mStartTint, mTargetTint, - animation.getAnimatedFraction()); - setBackgroundTintColor(newColor); + mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + int newColor = NotificationUtils.interpolateColors(mStartTint, mTargetTint, + animation.getAnimatedFraction()); + setBackgroundTintColor(newColor); + } }); mBackgroundColorAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); mBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR); @@ -570,11 +643,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } protected void updateBackgroundAlpha(float transformationAmount) { - float bgAlpha = isChildInGroup() && mDimmed ? transformationAmount : 1f; + mBgAlpha = isChildInGroup() && mDimmed ? transformationAmount : 1f; if (mDimmedBackgroundFadeInAmount != -1) { - bgAlpha *= mDimmedBackgroundFadeInAmount; + mBgAlpha *= mDimmedBackgroundFadeInAmount; } - mBackgroundDimmed.setAlpha(bgAlpha); + mBackgroundDimmed.setAlpha(mBgAlpha); } protected void resetBackgroundAlpha() { @@ -598,6 +671,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundDimmed.setVisibility(View.INVISIBLE); mBackgroundNormal.setVisibility(View.VISIBLE); mBackgroundNormal.setAlpha(1f); + removeCallbacks(mTapTimeoutRunnable); // make in inactive to avoid it sticking around active makeInactive(false /* animate */); } @@ -709,11 +783,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mAppearAnimator.setInterpolator(Interpolators.LINEAR); mAppearAnimator.setDuration( (long) (duration * Math.abs(mAppearAnimationFraction - targetValue))); - mAppearAnimator.addUpdateListener(animation -> { - mAppearAnimationFraction = (float) animation.getAnimatedValue(); - updateAppearAnimationAlpha(); - updateAppearRect(); - invalidate(); + mAppearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mAppearAnimationFraction = (float) animation.getAnimatedValue(); + updateAppearAnimationAlpha(); + updateAppearRect(); + invalidate(); + } }); if (animationListener != null) { mAppearAnimator.addListener(animationListener); @@ -844,7 +921,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView getCurrentBackgroundRadiusBottom()); } - private void applyBackgroundRoundness(float topRadius, float bottomRadius) { + protected void applyBackgroundRoundness(float topRadius, float bottomRadius) { mBackgroundDimmed.setRoundness(topRadius, bottomRadius); mBackgroundNormal.setRoundness(topRadius, bottomRadius); } @@ -886,7 +963,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } } - private int getRippleColor() { + protected int getRippleColor() { if (mBgTint != 0) { return mTintedRippleColor; } else { @@ -933,6 +1010,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mOnActivatedListener = onActivatedListener; } + public boolean hasSameBgColor(ActivatableNotificationView otherView) { + return calculateBgColor() == otherView.calculateBgColor(); + } + @Override public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd, int outlineTranslation) { @@ -990,20 +1071,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView return mRefocusOnDismiss || isAccessibilityFocused(); } - void setTouchHandler(Gefingerpoken touchHandler) { - mTouchHandler = touchHandler; - } - - void setOnDimmedListener(OnDimmedListener onDimmedListener) { - mOnDimmedListener = onDimmedListener; - } - public interface OnActivatedListener { void onActivated(ActivatableNotificationView view); void onActivationReset(ActivatableNotificationView view); } - - interface OnDimmedListener { - void onSetDimmed(boolean dimmed); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java index a6a1a4a3a56b..18993ffec357 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java @@ -16,13 +16,9 @@ package com.android.systemui.statusbar.notification.row; -import android.view.MotionEvent; -import android.view.View; import android.view.accessibility.AccessibilityManager; -import com.android.systemui.Gefingerpoken; import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.statusbar.phone.DoubleTapHelper; import javax.inject.Inject; @@ -31,106 +27,21 @@ import javax.inject.Inject; */ public class ActivatableNotificationViewController { private final ActivatableNotificationView mView; - private final ExpandableOutlineViewController mExpandableOutlineViewController; private final AccessibilityManager mAccessibilityManager; private final FalsingManager mFalsingManager; - private DoubleTapHelper mDoubleTapHelper; - private boolean mNeedsDimming; - - private TouchHandler mTouchHandler = new TouchHandler(); @Inject public ActivatableNotificationViewController(ActivatableNotificationView view, - ExpandableOutlineViewController expandableOutlineViewController, AccessibilityManager accessibilityManager, FalsingManager falsingManager) { mView = view; - mExpandableOutlineViewController = expandableOutlineViewController; mAccessibilityManager = accessibilityManager; mFalsingManager = falsingManager; - - mView.setOnActivatedListener(new ActivatableNotificationView.OnActivatedListener() { - @Override - public void onActivated(ActivatableNotificationView view) { - mFalsingManager.onNotificationActive(); - } - - @Override - public void onActivationReset(ActivatableNotificationView view) { - } - }); } /** * Initialize the controller, setting up handlers and other behavior. */ public void init() { - mExpandableOutlineViewController.init(); - mDoubleTapHelper = new DoubleTapHelper(mView, (active) -> { - if (active) { - mView.makeActive(); - mFalsingManager.onNotificationActive(); - } else { - mView.makeInactive(true /* animate */); - } - }, mView::performClick, mView::handleSlideBack, mFalsingManager::onNotificationDoubleTap); - mView.setOnTouchListener(mTouchHandler); - mView.setTouchHandler(mTouchHandler); - mView.setOnDimmedListener(dimmed -> { - mNeedsDimming = dimmed; - if (dimmed && !mAccessibilityManager.isTouchExplorationEnabled()) { - mView.setOnClickListener(null); - } else { - mView.setOnClickListener((v) -> mView.performClick()); - } - }); - } - - class TouchHandler implements Gefingerpoken, View.OnTouchListener { - private boolean mBlockNextTouch; - - @Override - public boolean onTouch(View v, MotionEvent ev) { - boolean result; - if (mBlockNextTouch) { - mBlockNextTouch = false; - return true; - } - if (mNeedsDimming && !mAccessibilityManager.isTouchExplorationEnabled() - && mView.isInteractive()) { - if (mNeedsDimming && !mView.isDimmed()) { - // We're actually dimmed, but our content isn't dimmable, - // let's ensure we have a ripple - return false; - } - result = mDoubleTapHelper.onTouchEvent(ev, mView.getActualHeight()); - } else { - return false; - } - return result; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (mNeedsDimming && ev.getActionMasked() == MotionEvent.ACTION_DOWN - && mView.disallowSingleClick(ev) - && !mAccessibilityManager.isTouchExplorationEnabled()) { - if (!mView.isActivated()) { - return true; - } else if (!mDoubleTapHelper.isWithinDoubleTapSlop(ev)) { - mBlockNextTouch = true; - mView.makeInactive(true /* animate */); - return true; - } - } - return false; - } - /** - * Use {@link #onTouch(View, MotionEvent) instead}. - */ - @Override - public boolean onTouchEvent(MotionEvent ev) { - return false; - } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 551731824570..c34bba782ad5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -42,6 +42,7 @@ import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; +import android.os.SystemClock; import android.service.notification.StatusBarNotification; import android.util.ArraySet; import android.util.AttributeSet; @@ -71,11 +72,11 @@ import com.android.internal.widget.CachingIconView; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarIconView; @@ -198,7 +199,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private NotificationGuts mGuts; private NotificationEntry mEntry; private String mAppName; - private FalsingManager mFalsingManager; /** * Whether or not the notification is using the heads up view and should peek from the top. @@ -1087,6 +1087,20 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mEntry.setInitializationTime(SystemClock.elapsedRealtime()); + Dependency.get(PluginManager.class).addPluginListener(this, + NotificationMenuRowPlugin.class, false /* Allow multiple */); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Dependency.get(PluginManager.class).removePluginListener(this); + } + + @Override public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) { boolean existed = mMenuRow != null && mMenuRow.getMenuView() != null; if (existed) { @@ -1425,7 +1439,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mIsBlockingHelperShowing && mNotificationTranslationFinished; } - void setOnDismissRunnable(Runnable onDismissRunnable) { + public void setOnDismissRunnable(Runnable onDismissRunnable) { mOnDismissRunnable = onDismissRunnable; } @@ -1583,6 +1597,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mMenuRow = new NotificationMenuRow(mContext); mImageResolver = new NotificationInlineImageResolver(context, new NotificationInlineImageCache()); + mMediaManager = Dependency.get(NotificationMediaManager.class); initDimens(); } @@ -1597,11 +1612,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView NotificationGroupManager groupManager, HeadsUpManager headsUpManager, RowContentBindStage rowContentBindStage, - OnExpandClickListener onExpandClickListener, - NotificationMediaManager notificationMediaManager, - OnAppOpsClickListener onAppOpsClickListener, - FalsingManager falsingManager, - StatusBarStateController statusBarStateController) { + OnExpandClickListener onExpandClickListener) { mAppName = appName; if (mMenuRow != null && mMenuRow.getMenuView() != null) { mMenuRow.setAppName(mAppName); @@ -1614,9 +1625,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mHeadsUpManager = headsUpManager; mRowContentBindStage = rowContentBindStage; mOnExpandClickListener = onExpandClickListener; - mMediaManager = notificationMediaManager; - setAppOpsOnClickListener(onAppOpsClickListener); - mFalsingManager = falsingManager; + } + + public void setStatusBarStateController(StatusBarStateController statusBarStateController) { mStatusbarStateController = statusBarStateController; } @@ -1708,7 +1719,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mOnAppOpsClickListener; } - void setAppOpsOnClickListener(ExpandableNotificationRow.OnAppOpsClickListener l) { + public void setAppOpsOnClickListener(ExpandableNotificationRow.OnAppOpsClickListener l) { mOnAppOpsClickListener = v -> { createMenu(); NotificationMenuRowPlugin provider = getProvider(); @@ -2177,7 +2188,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * @param allowChildExpansion whether a call to this method allows expanding children */ public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) { - mFalsingManager.setNotificationExpanded(); + getFalsingManager().setNotificationExpanded(); if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion && !mChildrenContainer.showingAsLowPriority()) { final boolean wasExpanded = mGroupManager.isGroupExpanded(mEntry.getSbn()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java deleted file mode 100644 index 39fab439ad07..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.statusbar.notification.row; - -import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; -import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT; - -import android.view.View; -import android.view.ViewGroup; - -import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.notification.row.dagger.AppName; -import com.android.systemui.statusbar.notification.row.dagger.DismissRunnable; -import com.android.systemui.statusbar.notification.row.dagger.NotificationKey; -import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope; -import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.NotificationGroupManager; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.util.time.SystemClock; - -import javax.inject.Inject; -import javax.inject.Named; - -/** - * Controller for {@link ExpandableNotificationRow}. - */ -@NotificationRowScope -public class ExpandableNotificationRowController { - private final ExpandableNotificationRow mView; - private final ActivatableNotificationViewController mActivatableNotificationViewController; - private final NotificationMediaManager mMediaManager; - private final PluginManager mPluginManager; - private final SystemClock mClock; - private final String mAppName; - private final String mNotificationKey; - private final KeyguardBypassController mKeyguardBypassController; - private final NotificationGroupManager mNotificationGroupManager; - private final RowContentBindStage mRowContentBindStage; - private final NotificationLogger mNotificationLogger; - private final HeadsUpManager mHeadsUpManager; - private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener; - private final StatusBarStateController mStatusBarStateController; - private final NotificationRowContentBinder.InflationCallback mInflationCallback; - - private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger = - this::logNotificationExpansion; - private final ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener; - private final NotificationGutsManager mNotificationGutsManager; - private Runnable mOnDismissRunnable; - private final FalsingManager mFalsingManager; - private final boolean mAllowLongPress; - - @Inject - public ExpandableNotificationRowController(ExpandableNotificationRow view, - ActivatableNotificationViewController activatableNotificationViewController, - NotificationMediaManager mediaManager, PluginManager pluginManager, - SystemClock clock, @AppName String appName, @NotificationKey String notificationKey, - KeyguardBypassController keyguardBypassController, - NotificationGroupManager notificationGroupManager, - RowContentBindStage rowContentBindStage, - NotificationLogger notificationLogger, HeadsUpManager headsUpManager, - ExpandableNotificationRow.OnExpandClickListener onExpandClickListener, - StatusBarStateController statusBarStateController, - NotificationRowContentBinder.InflationCallback inflationCallback, - NotificationGutsManager notificationGutsManager, - @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, - @DismissRunnable Runnable onDismissRunnable, FalsingManager falsingManager) { - mView = view; - mActivatableNotificationViewController = activatableNotificationViewController; - mMediaManager = mediaManager; - mPluginManager = pluginManager; - mClock = clock; - mAppName = appName; - mNotificationKey = notificationKey; - mKeyguardBypassController = keyguardBypassController; - mNotificationGroupManager = notificationGroupManager; - mRowContentBindStage = rowContentBindStage; - mNotificationLogger = notificationLogger; - mHeadsUpManager = headsUpManager; - mOnExpandClickListener = onExpandClickListener; - mStatusBarStateController = statusBarStateController; - mInflationCallback = inflationCallback; - mNotificationGutsManager = notificationGutsManager; - mOnDismissRunnable = onDismissRunnable; - mOnAppOpsClickListener = mNotificationGutsManager::openGuts; - mAllowLongPress = allowLongPress; - mFalsingManager = falsingManager; - } - - /** - * Initialize the controller. - */ - public void init() { - mActivatableNotificationViewController.init(); - mView.initialize( - mAppName, - mNotificationKey, - mExpansionLogger, - mKeyguardBypassController, - mNotificationGroupManager, - mHeadsUpManager, - mRowContentBindStage, - mOnExpandClickListener, - mMediaManager, - mOnAppOpsClickListener, - mFalsingManager, - mStatusBarStateController - ); - mView.setOnDismissRunnable(mOnDismissRunnable); - mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - if (mAllowLongPress) { - mView.setLongPressListener(mNotificationGutsManager::openGuts); - } - if (ENABLE_REMOTE_INPUT) { - mView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); - } - - mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - mView.getEntry().setInitializationTime(mClock.elapsedRealtime()); - mPluginManager.addPluginListener(mView, - NotificationMenuRowPlugin.class, false /* Allow multiple */); - } - - @Override - public void onViewDetachedFromWindow(View v) { - mPluginManager.removePluginListener(mView); - } - }); - } - - private void logNotificationExpansion(String key, boolean userAction, boolean expanded) { - mNotificationLogger.onExpansionChanged(key, userAction, expanded); - } - - /** */ - public void setOnDismissRunnable(Runnable onDismissRunnable) { - mOnDismissRunnable = onDismissRunnable; - mView.setOnDismissRunnable(onDismissRunnable); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineViewController.java deleted file mode 100644 index 75c9d1e6f2fc..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineViewController.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.statusbar.notification.row; - -import javax.inject.Inject; - -/** - * Controller for {@link ExpandableOutlineView}. - */ -public class ExpandableOutlineViewController { - private final ExpandableOutlineView mView; - private final ExpandableViewController mExpandableViewController; - - @Inject - public ExpandableOutlineViewController(ExpandableOutlineView view, - ExpandableViewController expandableViewController) { - mView = view; - mExpandableViewController = expandableViewController; - } - - /** - * Initialize the controller. - */ - public void init() { - mExpandableViewController.init(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java index 6feffe654630..c173b4dbaebe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java @@ -26,6 +26,7 @@ import androidx.asynclayoutinflater.view.AsyncLayoutInflater; import com.android.systemui.R; import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; import javax.inject.Inject; @@ -36,6 +37,7 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf private static final String TAG = "RowInflaterTask"; private static final boolean TRACE_ORIGIN = true; + private final NotificationRowComponent.Builder mNotificationRowComponentBuilder; private RowInflationFinishedListener mListener; private NotificationEntry mEntry; @@ -43,7 +45,10 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf private Throwable mInflateOrigin; @Inject - public RowInflaterTask() { + public RowInflaterTask( + NotificationRowComponent.Builder notificationRowComponentBuilder) { + super(); + mNotificationRowComponentBuilder = notificationRowComponentBuilder; } /** @@ -70,6 +75,12 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf public void onInflateFinished(View view, int resid, ViewGroup parent) { if (!mCancelled) { try { + // Setup the controller for the view. + NotificationRowComponent component = mNotificationRowComponentBuilder + .activatableNotificationView((ActivatableNotificationView) view) + .build(); + component.getActivatableNotificationViewController().init(); + mEntry.onInflationTaskFinished(); mListener.onInflationFinished((ExpandableNotificationRow) view); } catch (Throwable t) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ActivatableNotificationViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ActivatableNotificationViewModule.java deleted file mode 100644 index a3dfa608c709..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ActivatableNotificationViewModule.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.statusbar.notification.row.dagger; - -import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; -import com.android.systemui.statusbar.notification.row.ExpandableOutlineView; -import com.android.systemui.statusbar.notification.row.ExpandableView; - -import dagger.Binds; -import dagger.Module; - -/** - * Module for NotificationRowComponent. - */ -@Module -public interface ActivatableNotificationViewModule { - /** ExpandableView is provided as an instance of ActivatableNotificationView. */ - @Binds - ExpandableView bindExpandableView(ActivatableNotificationView view); - /** ExpandableOutlineView is provided as an instance of ActivatableNotificationView. */ - @Binds - ExpandableOutlineView bindExpandableOutlineView(ActivatableNotificationView view); -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/DismissRunnable.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/DismissRunnable.java deleted file mode 100644 index 433114224289..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/DismissRunnable.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.statusbar.notification.row.dagger; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; - -import javax.inject.Qualifier; - -@Qualifier -@Documented -@Retention(RUNTIME) -public @interface DismissRunnable { -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java deleted file mode 100644 index 6d6d3e446f53..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.statusbar.notification.row.dagger; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.service.notification.StatusBarNotification; - -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; -import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder; -import com.android.systemui.statusbar.notification.row.RowContentBindStage; -import com.android.systemui.statusbar.phone.StatusBar; - -import dagger.Binds; -import dagger.BindsInstance; -import dagger.Module; -import dagger.Provides; -import dagger.Subcomponent; - -/** - * Dagger Component for a {@link ExpandableNotificationRow}. - */ -@Subcomponent(modules = {ExpandableNotificationRowComponent.ExpandableNotificationRowModule.class, - ActivatableNotificationViewModule.class}) -@NotificationRowScope -public interface ExpandableNotificationRowComponent { - - /** - * Builder for {@link NotificationRowComponent}. - */ - @Subcomponent.Builder - interface Builder { - // TODO: NotificationEntry contains a reference to ExpandableNotificationRow, so it - // should be possible to pull one from the other, but they aren't connected at the time - // this component is constructed. - @BindsInstance - Builder expandableNotificationRow(ExpandableNotificationRow view); - @BindsInstance - Builder notificationEntry(NotificationEntry entry); - @BindsInstance - Builder onDismissRunnable(@DismissRunnable Runnable runnable); - @BindsInstance - Builder rowContentBindStage(RowContentBindStage rowContentBindStage); - @BindsInstance - Builder inflationCallback(NotificationRowContentBinder.InflationCallback inflationCallback); - @BindsInstance - Builder onExpandClickListener(ExpandableNotificationRow.OnExpandClickListener presenter); - ExpandableNotificationRowComponent build(); - } - - /** - * Creates a ExpandableNotificationRowController. - */ - @NotificationRowScope - ExpandableNotificationRowController getExpandableNotificationRowController(); - - /** - * Dagger Module that extracts interesting properties from an ExpandableNotificationRow. - */ - @Module - abstract class ExpandableNotificationRowModule { - - /** ExpandableNotificationRow is provided as an instance of ActivatableNotificationView. */ - @Binds - abstract ActivatableNotificationView bindExpandableView(ExpandableNotificationRow view); - - @Provides - static StatusBarNotification provideStatusBarNotification( - NotificationEntry notificationEntry) { - return notificationEntry.getSbn(); - } - - @Provides - @NotificationKey - static String provideNotificationKey(StatusBarNotification statusBarNotification) { - return statusBarNotification.getKey(); - } - - @Provides - @AppName - static String provideAppName(Context context, StatusBarNotification statusBarNotification) { - // Get the app name. - // Note that Notification.Builder#bindHeaderAppName has similar logic - // but since this field is used in the guts, it must be accurate. - // Therefore we will only show the application label, or, failing that, the - // package name. No substitutions. - PackageManager pmUser = StatusBar.getPackageManagerForUser( - context, statusBarNotification.getUser().getIdentifier()); - final String pkg = statusBarNotification.getPackageName(); - try { - final ApplicationInfo info = pmUser.getApplicationInfo(pkg, - PackageManager.MATCH_UNINSTALLED_PACKAGES - | PackageManager.MATCH_DISABLED_COMPONENTS); - if (info != null) { - return String.valueOf(pmUser.getApplicationLabel(info)); - } - } catch (PackageManager.NameNotFoundException e) { - // Do nothing - } - - return pkg; - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationKey.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationKey.java deleted file mode 100644 index b1fff383cd5d..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationKey.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.statusbar.notification.row.dagger; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; - -import javax.inject.Qualifier; - -@Qualifier -@Documented -@Retention(RUNTIME) -public @interface NotificationKey { -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationRowComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationRowComponent.java index 1f535c5e3f56..f16ea7ae23e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationRowComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationRowComponent.java @@ -16,17 +16,24 @@ package com.android.systemui.statusbar.notification.row.dagger; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + import dagger.BindsInstance; import dagger.Subcomponent; /** * Dagger subcomponent for Notification related views. */ -@Subcomponent(modules = {ActivatableNotificationViewModule.class}) -@NotificationRowScope +@Subcomponent(modules = {}) +@NotificationRowComponent.NotificationRowScope public interface NotificationRowComponent { /** * Builder for {@link NotificationRowComponent}. @@ -39,6 +46,14 @@ public interface NotificationRowComponent { } /** + * Scope annotation for singleton items within the StatusBarComponent. + */ + @Documented + @Retention(RUNTIME) + @Scope + @interface NotificationRowScope {} + + /** * Creates a ActivatableNotificationViewController. */ @NotificationRowScope diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationRowScope.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationRowScope.java deleted file mode 100644 index 4555b839a3f2..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationRowScope.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.statusbar.notification.row.dagger; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; - -import javax.inject.Scope; - -/** - * Scope annotation for singleton items within the StatusBarComponent. - */ -@Documented -@Retention(RUNTIME) -@Scope -public @interface NotificationRowScope {} diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt index cfd77be9303d..f4157f21e158 100644 --- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt +++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt @@ -901,6 +901,23 @@ class PhysicsAnimator<T> private constructor (val target: T) { verboseLogging = debug } + /** + * Estimates the end value of a fling that starts at the given value using the provided + * start velocity and fling configuration. + * + * This is only an estimate. Fling animations use a timing-based physics simulation that is + * non-deterministic, so this exact value may not be reached. + */ + @JvmStatic + fun estimateFlingEndValue( + startValue: Float, + startVelocity: Float, + flingConfig: FlingConfig + ): Float { + val distance = startVelocity / (flingConfig.friction * FLING_FRICTION_SCALAR_MULTIPLIER) + return Math.min(flingConfig.max, Math.max(flingConfig.min, startValue + distance)) + } + @JvmStatic fun getReadablePropertyName(property: FloatPropertyCompat<*>): String { return when (property) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt index 4becd522ebd6..9fe2569177d7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt @@ -88,8 +88,8 @@ class CustomTileTest : SysuiTestCase() { } @Test - fun testBooleanTileHasBooleanState() { - `when`(mTileServiceManager.isBooleanTile).thenReturn(true) + fun testToggleableTileHasBooleanState() { + `when`(mTileServiceManager.isToggleableTile).thenReturn(true) customTile = CustomTile.create(mTileHost, TILE_SPEC) assertTrue(customTile.state is QSTile.BooleanState) @@ -104,7 +104,7 @@ class CustomTileTest : SysuiTestCase() { @Test fun testValueUpdatedInBooleanTile() { - `when`(mTileServiceManager.isBooleanTile).thenReturn(true) + `when`(mTileServiceManager.isToggleableTile).thenReturn(true) customTile = CustomTile.create(mTileHost, TILE_SPEC) customTile.qsTile.icon = mock(Icon::class.java) `when`(customTile.qsTile.icon.loadDrawable(any(Context::class.java))) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java index 9e5e582bf5e7..42fd288d94ee 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java @@ -105,7 +105,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase { defaultServiceInfo = new ServiceInfo(); defaultServiceInfo.metaData = new Bundle(); defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_ACTIVE_TILE, true); - defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_BOOLEAN_TILE, true); + defaultServiceInfo.metaData.putBoolean(TileService.META_DATA_TOGGLEABLE_TILE, true); } when(mMockPackageManagerAdapter.getServiceInfo(any(), anyInt(), anyInt())) .thenReturn(defaultServiceInfo); @@ -244,7 +244,7 @@ public class TileLifecycleManagerTest extends SysuiTestCase { } @Test - public void testBooleanTile() throws Exception { - assertTrue(mStateManager.isBooleanTile()); + public void testToggleableTile() throws Exception { + assertTrue(mStateManager.isToggleableTile()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 5a0a495e1f85..07f6936ece07 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -58,13 +58,10 @@ import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; import com.android.internal.statusbar.NotificationVisibility; -import com.android.internal.util.NotificationMessagingUtil; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -86,13 +83,12 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; import com.android.systemui.statusbar.notification.row.NotifBindPipeline; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.RowContentBindParams; import com.android.systemui.statusbar.notification.row.RowContentBindStage; import com.android.systemui.statusbar.notification.row.RowInflaterTask; -import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; +import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -100,7 +96,6 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.Assert; import com.android.systemui.util.leak.LeakDetector; -import com.android.systemui.util.time.FakeSystemClock; import org.junit.After; import org.junit.Before; @@ -111,7 +106,6 @@ import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Arrays; @@ -147,13 +141,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Mock private NotificationEntryManagerLogger mLogger; @Mock private FeatureFlags mFeatureFlags; @Mock private LeakDetector mLeakDetector; - @Mock private NotificationMediaManager mNotificationMediaManager; - @Mock private ExpandableNotificationRowComponent.Builder - mExpandableNotificationRowComponentBuilder; - @Mock private ExpandableNotificationRowComponent mExpandableNotificationRowComponent; - @Mock private FalsingManager mFalsingManager; - @Mock private KeyguardBypassController mKeyguardBypassController; - @Mock private StatusBarStateController mStatusBarStateController; + @Mock private ActivatableNotificationViewController mActivatableNotificationViewController; + @Mock private NotificationRowComponent.Builder mNotificationRowComponentBuilder; private int mId; private NotificationEntry mEntry; @@ -202,6 +191,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); mDependency.injectMockDependency(SmartReplyController.class); + mDependency.injectMockDependency(NotificationMediaManager.class); mCountDownLatch = new CountDownLatch(1); @@ -217,23 +207,28 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntry.expandedIcon = mock(StatusBarIconView.class); + when(mNotificationRowComponentBuilder.activatableNotificationView(any())) + .thenReturn(mNotificationRowComponentBuilder); + when(mNotificationRowComponentBuilder.build()).thenReturn( + () -> mActivatableNotificationViewController); + RowContentBindStage bindStage = mock(RowContentBindStage.class); when(bindStage.getStageParams(any())).thenReturn(new RowContentBindParams()); + NotificationRowBinderImpl notificationRowBinder = new NotificationRowBinderImpl(mContext, - new NotificationMessagingUtil(mContext), mRemoteInputManager, mLockscreenUserManager, mock(NotifBindPipeline.class), bindStage, true, /* allowLongPress */ - mKeyguardBypassController, - mStatusBarStateController, + mock(KeyguardBypassController.class), + mock(StatusBarStateController.class), mGroupManager, mGutsManager, mNotificationInterruptionStateProvider, - RowInflaterTask::new, - mExpandableNotificationRowComponentBuilder); + () -> new RowInflaterTask(mNotificationRowComponentBuilder), + mock(NotificationLogger.class)); when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false); when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false); @@ -241,7 +236,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mLogger, mGroupManager, new NotificationRankingManager( - () -> mNotificationMediaManager, + () -> mock(NotificationMediaManager.class), mGroupManager, mHeadsUpManager, mock(NotificationFilter.class), @@ -260,55 +255,13 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntryManager.addNotificationEntryListener(mEntryListener); mEntryManager.addNotificationRemoveInterceptor(mRemoveInterceptor); - notificationRowBinder.setUpWithPresenter(mPresenter, mListContainer, mBindCallback); + notificationRowBinder.setUpWithPresenter( + mPresenter, mListContainer, mHeadsUpManager, mBindCallback); notificationRowBinder.setInflationCallback(mEntryManager); notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class)); setUserSentiment( mEntry.getKey(), Ranking.USER_SENTIMENT_NEUTRAL); - - ArgumentCaptor<ExpandableNotificationRow> viewCaptor = - ArgumentCaptor.forClass(ExpandableNotificationRow.class); - when(mExpandableNotificationRowComponentBuilder - .expandableNotificationRow(viewCaptor.capture())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - when(mExpandableNotificationRowComponentBuilder - .notificationEntry(any())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - when(mExpandableNotificationRowComponentBuilder - .onDismissRunnable(any())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - when(mExpandableNotificationRowComponentBuilder - .inflationCallback(any())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - when(mExpandableNotificationRowComponentBuilder - .onExpandClickListener(any())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - - when(mExpandableNotificationRowComponentBuilder.build()) - .thenReturn(mExpandableNotificationRowComponent); - when(mExpandableNotificationRowComponent.getExpandableNotificationRowController()) - .thenAnswer((Answer<ExpandableNotificationRowController>) invocation -> - new ExpandableNotificationRowController( - viewCaptor.getValue(), - mock(ActivatableNotificationViewController.class), - mNotificationMediaManager, - mock(PluginManager.class), - new FakeSystemClock(), - "FOOBAR", "FOOBAR", - mKeyguardBypassController, - mGroupManager, - bindStage, - mock(NotificationLogger.class), - mHeadsUpManager, - mPresenter, - mStatusBarStateController, - mEntryManager, - mGutsManager, - true, - null, - mFalsingManager - )); } @After diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index a8918103c4a2..d8cf6ed9a47b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -194,8 +194,9 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { @Test public void testClickSound() throws Exception { assertTrue("Should play sounds by default.", mGroupRow.isSoundEffectsEnabled()); - StatusBarStateController mock = mNotificationTestHelper.getStatusBarStateController(); + StatusBarStateController mock = mock(StatusBarStateController.class); when(mock.isDozing()).thenReturn(true); + mGroupRow.setStatusBarStateController(mock); mGroupRow.setSecureStateProvider(()-> false); assertFalse("Shouldn't play sounds when dark and trusted.", mGroupRow.isSoundEffectsEnabled()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index 35b55087873b..9b2e0c375e87 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -45,7 +45,6 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.TestableDependency; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.bubbles.BubblesTestActivity; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -92,7 +91,6 @@ public class NotificationTestHelper { private final NotifBindPipeline mBindPipeline; private final NotificationEntryListener mBindPipelineEntryListener; private final RowContentBindStage mBindStage; - private StatusBarStateController mStatusBarStateController; public NotificationTestHelper(Context context, TestableDependency dependency) { mContext = context; @@ -100,9 +98,9 @@ public class NotificationTestHelper { dependency.injectMockDependency(BubbleController.class); dependency.injectMockDependency(NotificationShadeWindowController.class); dependency.injectMockDependency(SmartReplyController.class); - mStatusBarStateController = mock(StatusBarStateController.class); - mGroupManager = new NotificationGroupManager(mStatusBarStateController); - mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarStateController, + StatusBarStateController stateController = mock(StatusBarStateController.class); + mGroupManager = new NotificationGroupManager(stateController); + mHeadsUpManager = new HeadsUpManagerPhone(mContext, stateController, mock(KeyguardBypassController.class)); mHeadsUpManager.setUp(null, mGroupManager, null, null); mGroupManager.setHeadsUpManager(mHeadsUpManager); @@ -323,10 +321,6 @@ public class NotificationTestHelper { return notificationBuilder.build(); } - public StatusBarStateController getStatusBarStateController() { - return mStatusBarStateController; - } - private ExpandableNotificationRow generateRow( Notification notification, String pkg, @@ -388,11 +382,7 @@ public class NotificationTestHelper { mGroupManager, mHeadsUpManager, mBindStage, - mock(OnExpandClickListener.class), - mock(NotificationMediaManager.class), - mock(ExpandableNotificationRow.OnAppOpsClickListener.class), - mock(FalsingManager.class), - mStatusBarStateController); + mock(OnExpandClickListener.class)); row.setAboveShelfChangedListener(aboveShelf -> { }); mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags); inflateAndWait(entry, mBindStage); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java index 2d1bc7890aed..e84f14a6a2c1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java @@ -30,6 +30,7 @@ import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -58,6 +59,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase { private ExpandableNotificationRow mFirst; private ExpandableNotificationRow mSecond; @Mock + private StatusBarStateController mStatusBarStateController; + @Mock private KeyguardBypassController mBypassController; @Before @@ -147,12 +150,13 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase { createSection(mFirst, mSecond), createSection(null, null) }); - NotificationTestHelper testHelper = new NotificationTestHelper(getContext(), mDependency); - ExpandableNotificationRow row = testHelper.createRow(); + ExpandableNotificationRow row = new NotificationTestHelper(getContext(), mDependency) + .createRow(); NotificationEntry entry = mock(NotificationEntry.class); when(entry.getRow()).thenReturn(row); - when(testHelper.getStatusBarStateController().isDozing()).thenReturn(true); + when(mStatusBarStateController.isDozing()).thenReturn(true); + row.setStatusBarStateController(mStatusBarStateController); row.setHeadsUp(true); mRoundnessManager.onHeadsUpStateChanged(entry, true); Assert.assertEquals(1f, row.getCurrentBottomRoundness(), 0.0f); diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 1cb9313d9bf9..4474f608f955 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -82,6 +82,7 @@ import com.android.server.LocalServices; import com.android.server.autofill.AutofillManagerService.AutofillCompatState; import com.android.server.autofill.RemoteAugmentedAutofillService.RemoteAugmentedAutofillServiceCallbacks; import com.android.server.autofill.ui.AutoFillUI; +import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.infra.AbstractPerUserSystemService; import com.android.server.inputmethod.InputMethodManagerInternal; @@ -180,6 +181,8 @@ final class AutofillManagerServiceImpl private final InputMethodManagerInternal mInputMethodManagerInternal; + private final ContentCaptureManagerInternal mContentCaptureManagerInternal; + AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui, AutofillCompatState autofillCompatState, @@ -192,10 +195,22 @@ final class AutofillManagerServiceImpl mFieldClassificationStrategy = new FieldClassificationStrategy(getContext(), userId); mAutofillCompatState = autofillCompatState; mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class); + mContentCaptureManagerInternal = LocalServices.getService( + ContentCaptureManagerInternal.class); updateLocked(disabled); } + boolean sendActivityAssistDataToContentCapture(@NonNull IBinder activityToken, + @NonNull Bundle data) { + if (mContentCaptureManagerInternal != null) { + mContentCaptureManagerInternal.sendActivityAssistData(getUserId(), activityToken, data); + return true; + } + + return false; + } + @GuardedBy("mLock") void onBackKeyPressed() { final RemoteAugmentedAutofillService remoteService = diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java new file mode 100644 index 000000000000..1fc48d235add --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2020 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.server.autofill; + +import static com.android.server.autofill.Helper.sDebug; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.os.RemoteException; +import android.util.Log; +import android.view.autofill.AutofillId; +import android.view.inputmethod.InlineSuggestionsRequest; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.view.IInlineSuggestionsRequestCallback; +import com.android.internal.view.IInlineSuggestionsResponseCallback; +import com.android.server.inputmethod.InputMethodManagerInternal; + +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * Maintains an inline suggestion autofill session. + * + * <p> This class is thread safe. + */ +final class InlineSuggestionSession { + + private static final String TAG = "InlineSuggestionSession"; + private static final int INLINE_REQUEST_TIMEOUT_MS = 1000; + + @NonNull + private final InputMethodManagerInternal mInputMethodManagerInternal; + private final int mUserId; + @NonNull + private final ComponentName mComponentName; + @NonNull + private final Object mLock; + + @GuardedBy("mLock") + @Nullable + private CompletableFuture<ImeResponse> mPendingImeResponse; + + InlineSuggestionSession(InputMethodManagerInternal inputMethodManagerInternal, + int userId, ComponentName componentName) { + mInputMethodManagerInternal = inputMethodManagerInternal; + mUserId = userId; + mComponentName = componentName; + mLock = new Object(); + } + + public void createRequest(@NonNull AutofillId currentViewId) { + synchronized (mLock) { + cancelCurrentRequest(); + mPendingImeResponse = new CompletableFuture<>(); + mInputMethodManagerInternal.onCreateInlineSuggestionsRequest( + mUserId, mComponentName, currentViewId, + new InlineSuggestionsRequestCallbackImpl(mPendingImeResponse)); + } + } + + @Nullable + public ImeResponse waitAndGetImeResponse() { + CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse(); + if (pendingImeResponse == null || pendingImeResponse.isCancelled()) { + return null; + } + try { + return pendingImeResponse.get(INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (TimeoutException e) { + Log.w(TAG, "Exception getting inline suggestions request in time: " + e); + } catch (CancellationException e) { + Log.w(TAG, "Inline suggestions request cancelled"); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + return null; + } + + private void cancelCurrentRequest() { + CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse(); + if (pendingImeResponse != null) { + pendingImeResponse.cancel(true); + } + } + + @Nullable + @GuardedBy("mLock") + private CompletableFuture<ImeResponse> getPendingImeResponse() { + synchronized (mLock) { + return mPendingImeResponse; + } + } + + private static final class InlineSuggestionsRequestCallbackImpl + extends IInlineSuggestionsRequestCallback.Stub { + + private final CompletableFuture<ImeResponse> mResponse; + + private InlineSuggestionsRequestCallbackImpl(CompletableFuture<ImeResponse> response) { + mResponse = response; + } + + @Override + public void onInlineSuggestionsUnsupported() throws RemoteException { + if (sDebug) { + Log.d(TAG, "onInlineSuggestionsUnsupported() called."); + } + mResponse.cancel(true); + } + + @Override + public void onInlineSuggestionsRequest(InlineSuggestionsRequest request, + IInlineSuggestionsResponseCallback callback) throws RemoteException { + if (sDebug) { + Log.d(TAG, "onInlineSuggestionsRequest() received: " + request); + } + if (request != null && callback != null) { + mResponse.complete(new ImeResponse(request, callback)); + } else { + mResponse.cancel(true); + } + } + } + + /** + * A data class wrapping IME responses for the inline suggestion request. + */ + public static class ImeResponse { + @NonNull + private final InlineSuggestionsRequest mRequest; + + @NonNull + private final IInlineSuggestionsResponseCallback mCallback; + + ImeResponse(@NonNull InlineSuggestionsRequest request, + @NonNull IInlineSuggestionsResponseCallback callback) { + mRequest = request; + mCallback = callback; + } + + public InlineSuggestionsRequest getRequest() { + return mRequest; + } + + public IInlineSuggestionsResponseCallback getCallback() { + return mCallback; + } + } +} diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 2fc116e504ee..53f85ea7b119 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -100,7 +100,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; -import com.android.internal.view.IInlineSuggestionsRequestCallback; import com.android.internal.view.IInlineSuggestionsResponseCallback; import com.android.server.autofill.ui.AutoFillUI; import com.android.server.autofill.ui.InlineSuggestionFactory; @@ -114,11 +113,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; /** @@ -159,9 +153,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState /** uid the session is for */ public final int uid; - /** user id the session is for */ - public final int userId; - /** ID of the task associated with this session's activity */ public final int taskId; @@ -310,12 +301,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private boolean mForAugmentedAutofillOnly; - @NonNull - private final InputMethodManagerInternal mInputMethodManagerInternal; - @Nullable - @GuardedBy("mLock") - private InlineSuggestionsRequestCallbackImpl mInlineSuggestionsRequestCallback; + private final InlineSuggestionSession mInlineSuggestionSession; /** * Receiver of assist data from the app's {@link Activity}. @@ -416,14 +403,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final ArrayList<FillContext> contexts = mergePreviousSessionLocked(/* forSave= */ false); - final InlineSuggestionsRequest suggestionsRequest = - mInlineSuggestionsRequestCallback != null - ? mInlineSuggestionsRequestCallback.getRequest() : null; + final InlineSuggestionSession.ImeResponse imeResponse = + mInlineSuggestionSession.waitAndGetImeResponse(); request = new FillRequest(requestId, contexts, mClientState, flags, - suggestionsRequest); + imeResponse != null ? imeResponse.getRequest() : null); } + if (mActivityToken != null) { + mService.sendActivityAssistDataToContentCapture(mActivityToken, resultData); + } mRemoteFillService.onFillRequest(request); } @@ -616,75 +605,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private void maybeRequestInlineSuggestionsRequestThenFillLocked(@NonNull ViewState viewState, int newState, int flags) { if (isInlineSuggestionsEnabled()) { - mInlineSuggestionsRequestCallback = new InlineSuggestionsRequestCallbackImpl(); - mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(userId, - mComponentName, mCurrentViewId, mInlineSuggestionsRequestCallback); + mInlineSuggestionSession.createRequest(mCurrentViewId); } requestNewFillResponseLocked(viewState, newState, flags); } - private static final class InlineSuggestionsRequestCallbackImpl - extends IInlineSuggestionsRequestCallback.Stub { - private static final int INLINE_REQUEST_TIMEOUT_MS = 1000; - - private final CompletableFuture<InlineSuggestionsRequest> mRequest; - private final CompletableFuture<IInlineSuggestionsResponseCallback> mResponseCallback; - - private InlineSuggestionsRequestCallbackImpl() { - mRequest = new CompletableFuture<>(); - mResponseCallback = new CompletableFuture<>(); - } - - @Override - public void onInlineSuggestionsUnsupported() throws RemoteException { - if (sDebug) { - Log.d(TAG, "inline suggestions request unsupported, " - + "falling back to regular autofill"); - } - mRequest.cancel(true); - mResponseCallback.cancel(true); - } - - @Override - public void onInlineSuggestionsRequest(InlineSuggestionsRequest request, - IInlineSuggestionsResponseCallback callback) throws RemoteException { - if (sDebug) { - Log.d(TAG, "onInlineSuggestionsRequest() received: " + request); - } - mRequest.complete(request); - mResponseCallback.complete(callback); - } - - @Nullable - private InlineSuggestionsRequest getRequest() { - try { - return mRequest.get(INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); - } catch (TimeoutException e) { - Log.w(TAG, "Exception getting inline suggestions request in time: " + e); - } catch (CancellationException e) { - Log.w(TAG, "Inline suggestions request cancelled"); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - return null; - } - - @Nullable - private IInlineSuggestionsResponseCallback getResponseCallback() { - try { - return mResponseCallback.get(INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); - } catch (TimeoutException e) { - Log.w(TAG, "Exception getting inline suggestions callback in time: " + e); - } catch (CancellationException e) { - Log.w(TAG, "Inline suggestions callback cancelled"); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - return null; - } - } - /** * Reads a new structure and then request a new fill response from the fill service. */ @@ -764,7 +690,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mFlags = flags; this.taskId = taskId; this.uid = uid; - this.userId = userId; mStartTime = SystemClock.elapsedRealtime(); mService = service; mLock = lock; @@ -783,7 +708,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mForAugmentedAutofillOnly = forAugmentedAutofillOnly; setClientLocked(client); - mInputMethodManagerInternal = inputMethodManagerInternal; + mInlineSuggestionSession = new InlineSuggestionSession(inputMethodManagerInternal, userId, + componentName); mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED) .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags)); @@ -2676,7 +2602,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (response.supportsInlineSuggestions()) { synchronized (mLock) { - if (requestShowInlineSuggestions(response, mInlineSuggestionsRequestCallback)) { + if (requestShowInlineSuggestionsLocked(response)) { //TODO(b/137800469): Fix it to log showed only when IME asks for inflation, // rather than here where framework sends back the response. mService.logDatasetShown(id, mClientState); @@ -2719,21 +2645,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState /** * Returns whether we made a request to show inline suggestions. */ - private boolean requestShowInlineSuggestions(@NonNull FillResponse response, - @Nullable InlineSuggestionsRequestCallbackImpl callback) { + private boolean requestShowInlineSuggestionsLocked(@NonNull FillResponse response) { final List<Dataset> datasets = response.getDatasets(); if (datasets == null) { Log.w(TAG, "response returned null datasets"); return false; } - if (callback == null || callback.getRequest() == null - || callback.getResponseCallback() == null) { + final InlineSuggestionSession.ImeResponse imeResponse = + mInlineSuggestionSession.waitAndGetImeResponse(); + if (imeResponse == null) { Log.w(TAG, "Session input method callback is not set yet"); return false; } - final InlineSuggestionsRequest request = callback.getRequest(); + final InlineSuggestionsRequest request = imeResponse.getRequest(); InlineSuggestionsResponse inlineSuggestionsResponse = InlineSuggestionFactory.createInlineSuggestionsResponse(request, response.getRequestId(), @@ -2744,7 +2670,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } }); try { - callback.getResponseCallback().onInlineSuggestionsResponse(inlineSuggestionsResponse); + imeResponse.getCallback().onInlineSuggestionsResponse(inlineSuggestionsResponse); } catch (RemoteException e) { Log.w(TAG, "onFillReady() remote error calling onInlineSuggestionsResponse()"); return false; @@ -3026,12 +2952,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final AutofillId focusedId = AutofillId.withoutSession(mCurrentViewId); + // There are 3 cases when augmented autofill should ask IME for a new request: + // 1. standard autofill provider is None + // 2. standard autofill provider doesn't support inline (and returns null response) + // 3. standard autofill provider supports inline, but isn't called because the field + // doesn't want autofill + if (mForAugmentedAutofillOnly || !isInlineSuggestionsEnabled()) { + if (sDebug) Slog.d(TAG, "Create inline request for augmented autofill"); + mInlineSuggestionSession.createRequest(mCurrentViewId); + } + InlineSuggestionSession.ImeResponse imeResponse = + mInlineSuggestionSession.waitAndGetImeResponse(); final InlineSuggestionsRequest inlineSuggestionsRequest = - mInlineSuggestionsRequestCallback != null - ? mInlineSuggestionsRequestCallback.getRequest() : null; + imeResponse != null ? imeResponse.getRequest() : null; final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback = - mInlineSuggestionsRequestCallback != null - ? mInlineSuggestionsRequestCallback.getResponseCallback() : null; + imeResponse != null ? imeResponse.getCallback() : null; remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, focusedId, currentValue, inlineSuggestionsRequest, inlineSuggestionsResponseCallback, () -> { synchronized (mLock) { diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index 583c5b593b88..32bca35009a8 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -426,18 +426,26 @@ final class ContentCapturePerUserService public boolean sendActivityAssistDataLocked(@NonNull IBinder activityToken, @NonNull Bundle data) { final int id = getSessionId(activityToken); + final Bundle assistData = data.getBundle(ASSIST_KEY_DATA); + final AssistStructure assistStructure = data.getParcelable(ASSIST_KEY_STRUCTURE); + final AssistContent assistContent = data.getParcelable(ASSIST_KEY_CONTENT); + final SnapshotData snapshotData = new SnapshotData(assistData, + assistStructure, assistContent); if (id != NO_SESSION_ID) { final ContentCaptureServerSession session = mSessions.get(id); - final Bundle assistData = data.getBundle(ASSIST_KEY_DATA); - final AssistStructure assistStructure = data.getParcelable(ASSIST_KEY_STRUCTURE); - final AssistContent assistContent = data.getParcelable(ASSIST_KEY_CONTENT); - final SnapshotData snapshotData = new SnapshotData(assistData, - assistStructure, assistContent); session.sendActivitySnapshotLocked(snapshotData); return true; - } else { - Slog.e(TAG, "Failed to notify activity assist data for activity: " + activityToken); } + + // We want to send an activity snapshot regardless of whether a content capture session is + // present or not since a content capture session is not required for this functionality + if (mRemoteService != null) { + mRemoteService.onActivitySnapshotRequest(NO_SESSION_ID, snapshotData); + Slog.d(TAG, "Notified activity assist data for activity: " + + activityToken + " without a session Id"); + return true; + } + return false; } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index cbf6c274e865..0e5a6bb8bd1c 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -284,16 +284,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { static final int ENFORCE_PHONE_STATE_PERMISSION_MASK = PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR - | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST - | PhoneStateListener.LISTEN_REGISTRATION_FAILURE - | PhoneStateListener.LISTEN_BARRING_INFO; + | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST; - static final int PRECISE_PHONE_STATE_PERMISSION_MASK = + static final int ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK = PhoneStateListener.LISTEN_PRECISE_CALL_STATE - | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE - | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES - | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED - | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES; + | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE + | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES + | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED + | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES + | PhoneStateListener.LISTEN_REGISTRATION_FAILURE + | PhoneStateListener.LISTEN_BARRING_INFO; static final int READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK = PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL @@ -2535,7 +2535,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) { + if ((events & ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) { // check if calling app has either permission READ_PRECISE_PHONE_STATE // or with carrier privileges try { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 3ad96ea193bf..6bff76c15edd 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -466,18 +466,9 @@ public class ActivityManagerService extends IActivityManager.Stub // How long we wait for a launched process to attach to the activity manager // before we decide it's never going to come up for real. static final int PROC_START_TIMEOUT = 10*1000; - // How long we wait for an attached process to publish its content providers - // before we decide it must be hung. - static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000; - // How long we wait to kill an application zygote, after the last process using // it has gone away. static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000; - /** - * How long we wait for an provider to be published. Should be longer than - * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT}. - */ - static final int CONTENT_PROVIDER_WAIT_TIMEOUT = 20 * 1000; // How long we wait for a launched process to attach to the activity manager // before we decide it's never going to come up for real, when the process was @@ -4934,7 +4925,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (providers != null && checkAppInLaunchingProvidersLocked(app)) { Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG); msg.obj = app; - mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT); + mHandler.sendMessageDelayed(msg, + ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS); } checkTime(startTime, "attachApplicationLocked: before bindApplication"); @@ -7201,7 +7193,8 @@ public class ActivityManagerService extends IActivityManager.Stub } // Wait for the provider to be published... - final long timeout = SystemClock.uptimeMillis() + CONTENT_PROVIDER_WAIT_TIMEOUT; + final long timeout = + SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS; boolean timedOut = false; synchronized (cpr) { while (cpr.provider == null) { @@ -7238,12 +7231,14 @@ public class ActivityManagerService extends IActivityManager.Stub } } if (timedOut) { - // Note we do it afer releasing the lock. + // Note we do it after releasing the lock. String callerName = "unknown"; - synchronized (this) { - final ProcessRecord record = mProcessList.getLRURecordForAppLocked(caller); - if (record != null) { - callerName = record.processName; + if (caller != null) { + synchronized (this) { + final ProcessRecord record = mProcessList.getLRURecordForAppLocked(caller); + if (record != null) { + callerName = record.processName; + } } } diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java index e8cb1632bdc3..061cbd8a1a40 100644 --- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java +++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java @@ -170,6 +170,11 @@ public class NotificationHistoryDatabase { mFileWriteHandler.post(rpr); } + public void deleteNotificationHistoryItem(String pkg, long postedTime) { + RemoveNotificationRunnable rnr = new RemoveNotificationRunnable(pkg, postedTime); + mFileWriteHandler.post(rnr); + } + public void addNotification(final HistoricalNotification notification) { synchronized (mLock) { mBuffer.addNewNotificationToWrite(notification); @@ -367,6 +372,49 @@ public class NotificationHistoryDatabase { } } + final class RemoveNotificationRunnable implements Runnable { + private String mPkg; + private long mPostedTime; + private NotificationHistory mNotificationHistory; + + public RemoveNotificationRunnable(String pkg, long postedTime) { + mPkg = pkg; + mPostedTime = postedTime; + } + + @VisibleForTesting + void setNotificationHistory(NotificationHistory nh) { + mNotificationHistory = nh; + } + + @Override + public void run() { + if (DEBUG) Slog.d(TAG, "RemovePackageRunnable"); + synchronized (mLock) { + // Remove from pending history + mBuffer.removeNotificationFromWrite(mPkg, mPostedTime); + + Iterator<AtomicFile> historyFileItr = mHistoryFiles.iterator(); + while (historyFileItr.hasNext()) { + final AtomicFile af = historyFileItr.next(); + try { + NotificationHistory notificationHistory = mNotificationHistory != null + ? mNotificationHistory + : new NotificationHistory(); + readLocked(af, notificationHistory, + new NotificationHistoryFilter.Builder().build()); + if(notificationHistory.removeNotificationFromWrite(mPkg, mPostedTime)) { + writeLocked(af, notificationHistory); + } + } catch (Exception e) { + Slog.e(TAG, "Cannot clean up file on notification removal " + + af.getBaseFile().getName(), e); + } + } + } + } + } + public static final class NotificationHistoryFileAttrProvider implements NotificationHistoryDatabase.FileAttrProvider { final static String TAG = "NotifHistoryFileDate"; diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java index 41bc29f7a82e..9aab0fd912e8 100644 --- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java +++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java @@ -130,7 +130,7 @@ public class NotificationHistoryManager { } } - public void onPackageRemoved(int userId, String packageName) { + public void onPackageRemoved(@UserIdInt int userId, String packageName) { synchronized (mLock) { if (!mUserUnlockedStates.get(userId, false)) { if (mHistoryEnabled.get(userId, false)) { @@ -150,6 +150,22 @@ public class NotificationHistoryManager { } } + public void deleteNotificationHistoryItem(String pkg, int uid, long postedTime) { + synchronized (mLock) { + int userId = UserHandle.getUserId(uid); + final NotificationHistoryDatabase userHistory = + getUserHistoryAndInitializeIfNeededLocked(userId); + // TODO: it shouldn't be possible to delete a notification entry while the user is + // locked but we should handle it + if (userHistory == null) { + Slog.w(TAG, "Attempted to remove notif for locked/gone/disabled user " + + userId); + return; + } + userHistory.deleteNotificationHistoryItem(pkg, postedTime); + } + } + // TODO: wire this up to AMS when power button is long pressed public void triggerWriteToDisk() { synchronized (mLock) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index f07113591fa5..f8777d618776 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2780,7 +2780,7 @@ public class NotificationManagerService extends SystemService { if (!isSystemToast) { int count = 0; final int N = mToastQueue.size(); - for (int i=0; i<N; i++) { + for (int i = 0; i < N; i++) { final ToastRecord r = mToastQueue.get(i); if (r.pkg.equals(pkg)) { count++; @@ -2820,7 +2820,7 @@ public class NotificationManagerService extends SystemService { if (pkg == null || token == null) { Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " token=" + token); - return ; + return; } synchronized (mToastQueue) { @@ -2933,14 +2933,14 @@ public class NotificationManagerService extends SystemService { /** * Updates the enabled state for notifications for the given package (and uid). - * Additionally, this method marks the app importance as locked by the user, which means + * Additionally, this method marks the app importance as locked by the user, which + * means * that notifications from the app will <b>not</b> be considered for showing a * blocking helper. * - * @param pkg package that owns the notifications to update - * @param uid uid of the app providing notifications + * @param pkg package that owns the notifications to update + * @param uid uid of the app providing notifications * @param enabled whether notifications should be enabled for the app - * * @see #setNotificationsEnabledForPackage(String, int, boolean) */ @Override @@ -3031,6 +3031,12 @@ public class NotificationManagerService extends SystemService { } @Override + public void deleteNotificationHistoryItem(String pkg, int uid, long postedTime) { + checkCallerIsSystem(); + mHistoryManager.deleteNotificationHistoryItem(pkg, uid, postedTime); + } + + @Override public int getPackageImportance(String pkg) { checkCallerIsSystemOrSameApp(pkg); return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid()); @@ -9256,7 +9262,7 @@ public class NotificationManagerService extends SystemService { } BackgroundThread.getHandler().post(() -> { - if (hasCompanionDevice(serviceInfo)) { + if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) { notifyNotificationChannelChanged( serviceInfo, pkg, user, channel, modificationType); } @@ -9276,7 +9282,7 @@ public class NotificationManagerService extends SystemService { } BackgroundThread.getHandler().post(() -> { - if (hasCompanionDevice(serviceInfo)) { + if (serviceInfo.isSystem || hasCompanionDevice(serviceInfo)) { notifyNotificationChannelGroupChanged( serviceInfo, pkg, user, group, modificationType); } diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 42bc464e943f..a440c62a5f3c 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -36,6 +36,7 @@ import android.content.pm.parsing.AndroidPackage; import android.os.Environment; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.Trace; import android.sysprop.ApexProperties; import android.util.ArrayMap; import android.util.ArraySet; @@ -46,6 +47,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.utils.TimingsTraceAndSlog; import com.google.android.collect.Lists; @@ -375,8 +377,11 @@ public abstract class ApexManager { @Override public List<ActiveApexInfo> getActiveApexInfos() { + final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", + Trace.TRACE_TAG_APEX_MANAGER); synchronized (mLock) { if (mActiveApexInfosCache == null) { + t.traceBegin("getActiveApexInfos_noCache"); try { mActiveApexInfosCache = new ArraySet<>(); final ApexInfo[] activePackages = mApexService.getActivePackages(); @@ -387,6 +392,7 @@ public abstract class ApexManager { } catch (RemoteException e) { Slog.e(TAG, "Unable to retrieve packages from apexservice", e); } + t.traceEnd(); } if (mActiveApexInfosCache != null) { return new ArrayList<>(mActiveApexInfosCache); diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 3ad120705eb3..8c13b5bf8519 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -34,6 +34,7 @@ import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo; import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; import android.content.pm.parsing.ComponentParseUtils.ParsedService; import android.net.Uri; +import android.os.Binder; import android.os.Process; import android.os.Trace; import android.os.UserHandle; @@ -171,11 +172,13 @@ public class AppsFilter { @Override public boolean packageIsEnabled(AndroidPackage pkg) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "packageIsEnabled"); + final long token = Binder.clearCallingIdentity(); try { // TODO(b/135203078): Do not use toAppInfo return mInjector.getCompatibility().isChangeEnabled( PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState()); } finally { + Binder.restoreCallingIdentity(token); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 3e64e9828c3e..0cd1c259dd9e 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -661,6 +661,23 @@ public class LauncherAppsService extends SystemService { } } + private void ensureStrictAccessShortcutsPermission(@NonNull String callingPackage) { + verifyCallingPackage(callingPackage); + if (!injectHasAccessShortcutsPermission(injectBinderCallingPid(), + injectBinderCallingUid())) { + throw new SecurityException("Caller can't access shortcut information"); + } + } + + /** + * Returns true if the caller has the "ACCESS_SHORTCUTS" permission. + */ + @VisibleForTesting + boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) { + return mContext.checkPermission(android.Manifest.permission.ACCESS_SHORTCUTS, + callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; + } + @Override public ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName, List shortcutIds, List<LocusId> locusIds, @@ -710,6 +727,30 @@ public class LauncherAppsService extends SystemService { } @Override + public void cacheShortcuts(String callingPackage, String packageName, List<String> ids, + UserHandle targetUser) { + ensureStrictAccessShortcutsPermission(callingPackage); + if (!canAccessProfile(targetUser.getIdentifier(), "Cannot cache shortcuts")) { + return; + } + + mShortcutServiceInternal.cacheShortcuts(getCallingUserId(), + callingPackage, packageName, ids, targetUser.getIdentifier()); + } + + @Override + public void uncacheShortcuts(String callingPackage, String packageName, List<String> ids, + UserHandle targetUser) { + ensureStrictAccessShortcutsPermission(callingPackage); + if (!canAccessProfile(targetUser.getIdentifier(), "Cannot uncache shortcuts")) { + return; + } + + mShortcutServiceInternal.uncacheShortcuts(getCallingUserId(), + callingPackage, packageName, ids, targetUser.getIdentifier()); + } + + @Override public int getShortcutIconResId(String callingPackage, String packageName, String id, int targetUserId) { ensureShortcutPermission(callingPackage); diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java index e550bae7484b..482fc4944691 100644 --- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java +++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java @@ -344,18 +344,10 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { int abi64 = PackageManager.NO_NATIVE_LIBRARIES; if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { if (extractLibs) { - if (onIncremental) { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, - "incrementalNativeBinaries"); - abi32 = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg, - handle, nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS, - useIsaSpecificSubdirs); - } else { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries"); - abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, - nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS, - useIsaSpecificSubdirs); - } + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries"); + abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, + nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS, + useIsaSpecificSubdirs, onIncremental); } else { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi"); abi32 = NativeLibraryHelper.findSupportedAbi( @@ -375,18 +367,10 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { if (extractLibs) { - if (onIncremental) { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, - "incrementalNativeBinaries"); - abi64 = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg, - handle, nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS, - useIsaSpecificSubdirs); - } else { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries"); - abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, - nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS, - useIsaSpecificSubdirs); - } + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries"); + abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, + nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS, + useIsaSpecificSubdirs, onIncremental); } else { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi"); abi64 = NativeLibraryHelper.findSupportedAbi( @@ -437,15 +421,9 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { final int copyRet; if (extractLibs) { - if (onIncremental) { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "incrementalNativeBinaries"); - copyRet = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg, - handle, nativeLibraryRoot, abiList, useIsaSpecificSubdirs); - } else { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries"); - copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, - nativeLibraryRoot, abiList, useIsaSpecificSubdirs); - } + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries"); + copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, + nativeLibraryRoot, abiList, useIsaSpecificSubdirs, onIncremental); } else { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi"); copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 0cf8b424b84d..944280d6db88 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1681,10 +1681,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mInternalProgress = 0.5f; computeProgressLocked(true); - // Unpack native libraries for non-incremental installation - if (!isIncrementalInstallation()) { - extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs()); - } + extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs()); } // We've reached point of no return; call into PMS to install the stage. @@ -2260,7 +2257,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir); } - private static void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit) + private void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit) throws PackageManagerException { final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME); if (!inherit) { @@ -2272,7 +2269,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { try { handle = NativeLibraryHelper.Handle.create(packageDir); final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir, - abiOverride); + abiOverride, isIncrementalInstallation()); if (res != PackageManager.INSTALL_SUCCEEDED) { throw new PackageManagerException(res, "Failed to extract native libraries, res=" + res); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 42b24839a36b..88c048cea267 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3627,7 +3627,7 @@ public class PackageManagerService extends IPackageManager.Stub try { handle = NativeLibraryHelper.Handle.create(dstCodePath); ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot, - null /*abiOverride*/); + null /*abiOverride*/, false /*isIncremental*/); } catch (IOException e) { logCriticalInfo(Log.ERROR, "Failed to extract native libraries" + "; pkg: " + packageName); @@ -14970,12 +14970,13 @@ public class PackageManagerService extends IPackageManager.Stub return ret; } + final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath()); final File libraryRoot = new File(codeFile, LIB_DIR_NAME); NativeLibraryHelper.Handle handle = null; try { handle = NativeLibraryHelper.Handle.create(codeFile); ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot, - abiOverride); + abiOverride, isIncremental); } catch (IOException e) { Slog.e(TAG, "Copying native libraries failed", e); ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index d16c0748ef0e..377fd16d4e19 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -1704,7 +1704,7 @@ public class ShortcutService extends IShortcutService.Stub { ShortcutInfo.validateIcon(shortcut.getIcon()); } - shortcut.replaceFlags(0); + shortcut.replaceFlags(shortcut.getFlags() & ShortcutInfo.FLAG_LONG_LIVED); } private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) { @@ -2758,6 +2758,68 @@ public class ShortcutService extends IShortcutService.Stub { } @Override + public void cacheShortcuts(int launcherUserId, + @NonNull String callingPackage, @NonNull String packageName, + @NonNull List<String> shortcutIds, int userId) { + updateCachedShortcutsInternal(launcherUserId, callingPackage, packageName, shortcutIds, + userId, /* doCache= */ true); + } + + @Override + public void uncacheShortcuts(int launcherUserId, + @NonNull String callingPackage, @NonNull String packageName, + @NonNull List<String> shortcutIds, int userId) { + updateCachedShortcutsInternal(launcherUserId, callingPackage, packageName, shortcutIds, + userId, /* doCache= */ false); + } + + private void updateCachedShortcutsInternal(int launcherUserId, + @NonNull String callingPackage, @NonNull String packageName, + @NonNull List<String> shortcutIds, int userId, boolean doCache) { + // Calling permission must be checked by LauncherAppsImpl. + Preconditions.checkStringNotEmpty(packageName, "packageName"); + Objects.requireNonNull(shortcutIds, "shortcutIds"); + + synchronized (mLock) { + throwIfUserLockedL(userId); + throwIfUserLockedL(launcherUserId); + + final int idSize = shortcutIds.size(); + final ShortcutPackage sp = getUserShortcutsLocked(userId) + .getPackageShortcutsIfExists(packageName); + if (idSize == 0 || sp == null) { + return; + } + + for (int i = 0; i < idSize; i++) { + final String id = Preconditions.checkStringNotEmpty(shortcutIds.get(i)); + final ShortcutInfo si = sp.findShortcutById(id); + if (si == null || doCache == si.isCached()) { + continue; + } + + if (doCache) { + if (si.isDynamic() && si.isLongLived()) { + si.addFlags(ShortcutInfo.FLAG_CACHED); + } else { + Log.w(TAG, "Only dynamic long lived shortcuts can get cached. Ignoring" + + "shortcut " + si.getId()); + } + } else { + if (si.isDynamic()) { + si.clearFlags(ShortcutInfo.FLAG_CACHED); + } else { + sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true); + } + } + } + } + packageShortcutsChanged(packageName, userId); + + verifyStates(); + } + + @Override public Intent[] createShortcutIntents(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, int userId, diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 0cb8f49540be..1c02161c5b96 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1901,7 +1901,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public boolean hasBaseUserRestriction(String restrictionKey, @UserIdInt int userId) { - checkManageUsersPermission("hasBaseUserRestriction"); + checkManageOrCreateUsersPermission("hasBaseUserRestriction"); if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) { return false; } diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 2c7795a6274b..43d45967f67b 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -39,9 +39,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.PackageListObserver; import android.content.pm.PermissionInfo; -import android.content.pm.parsing.AndroidPackage; import android.os.Build; -import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -52,14 +50,15 @@ import android.telecom.TelecomManager; import android.util.ArrayMap; import android.util.ArraySet; import android.util.LongSparseLongArray; -import android.util.Pair; import android.util.Slog; +import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.infra.AndroidFuture; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.IntPair; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.FgThread; @@ -70,6 +69,7 @@ import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.ExecutionException; /** @@ -100,7 +100,7 @@ public final class PermissionPolicyService extends SystemService { * scheduled for a package/user. */ @GuardedBy("mLock") - private final ArraySet<Pair<String, Integer>> mIsPackageSyncsScheduled = new ArraySet<>(); + private final ArraySet<Integer> mIsPackageSyncsScheduled = new ArraySet<>(); public PermissionPolicyService(@NonNull Context context) { super(context); @@ -125,10 +125,8 @@ public final class PermissionPolicyService extends SystemService { @Override public void onPackageChanged(String packageName, int uid) { - final int userId = UserHandle.getUserId(uid); - - if (isStarted(userId)) { - synchronizePackagePermissionsAndAppOpsForUser(packageName, userId); + if (isStarted(UserHandle.getUserId(uid))) { + synchronizePackagePermissionsAndAppOpsForUser(uid); } } @@ -139,12 +137,21 @@ public final class PermissionPolicyService extends SystemService { }); permManagerInternal.addOnRuntimePermissionStateChangedListener( - this::synchronizePackagePermissionsAndAppOpsAsyncForUser); + (packageName, userId) -> { + int uid; + try { + uid = getContext().getPackageManager().getPackageUidAsUser(packageName, 0, + userId); + } catch (NameNotFoundException e) { + Slog.e(LOG_TAG, "Cannot synchronize changed package " + packageName, e); + return; + } + synchronizeUidPermissionsAndAppOpsAsync(uid); + }); mAppOpsCallback = new IAppOpsCallback.Stub() { public void opChanged(int op, int uid, String packageName) { - synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName, - UserHandle.getUserId(uid)); + synchronizeUidPermissionsAndAppOpsAsync(uid); } }; @@ -194,19 +201,17 @@ public final class PermissionPolicyService extends SystemService { return AppOpsManager.opToSwitch(op); } - private void synchronizePackagePermissionsAndAppOpsAsyncForUser(@NonNull String packageName, - @UserIdInt int changedUserId) { - if (isStarted(changedUserId)) { + private void synchronizeUidPermissionsAndAppOpsAsync(int uid) { + if (isStarted(UserHandle.getUserId(uid))) { synchronized (mLock) { - if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) { + if (mIsPackageSyncsScheduled.add(uid)) { FgThread.getHandler().sendMessage(PooledLambda.obtainMessage( PermissionPolicyService ::synchronizePackagePermissionsAndAppOpsForUser, - this, packageName, changedUserId)); + this, uid)); } else { if (DEBUG) { - Slog.v(LOG_TAG, "sync for " + packageName + "/" + changedUserId - + " already scheduled"); + Slog.v(LOG_TAG, "sync for " + uid + " already scheduled"); } } } @@ -335,39 +340,20 @@ public final class PermissionPolicyService extends SystemService { /** * Synchronize a single package. */ - private void synchronizePackagePermissionsAndAppOpsForUser(@NonNull String packageName, - @UserIdInt int userId) { + private void synchronizePackagePermissionsAndAppOpsForUser(int uid) { synchronized (mLock) { - mIsPackageSyncsScheduled.remove(new Pair<>(packageName, userId)); + mIsPackageSyncsScheduled.remove(uid); } if (DEBUG) { Slog.v(LOG_TAG, - "synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", " - + userId + ")"); + "synchronizePackagePermissionsAndAppOpsForUser(" + uid + ")"); } - final PackageManagerInternal packageManagerInternal = LocalServices.getService( - PackageManagerInternal.class); - final PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName, 0, - Process.SYSTEM_UID, userId); - if (pkg == null) { - return; - } final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser( - getUserContext(getContext(), UserHandle.of(userId))); - synchroniser.addPackage(pkg.packageName); - final String[] sharedPkgNames = packageManagerInternal.getSharedUserPackagesForPackage( - pkg.packageName, userId); - - for (String sharedPkgName : sharedPkgNames) { - final AndroidPackage sharedPkg = packageManagerInternal - .getPackage(sharedPkgName); - if (sharedPkg != null) { - synchroniser.addPackage(sharedPkg.getPackageName()); - } - } - synchroniser.syncPackages(); + getUserContext(getContext(), UserHandle.getUserHandleForUid(uid))); + synchroniser.addUid(uid); + synchroniser.syncUids(); } /** @@ -381,8 +367,8 @@ public final class PermissionPolicyService extends SystemService { final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser( getUserContext(getContext(), UserHandle.of(userId))); packageManagerInternal.forEachPackage( - (pkg) -> synchronizer.addPackage(pkg.getPackageName())); - synchronizer.syncPackages(); + (pkg) -> synchronizer.addUid(pkg.getUid())); + synchronizer.syncUids(); } /** @@ -397,37 +383,51 @@ public final class PermissionPolicyService extends SystemService { private final @NonNull ArrayMap<String, PermissionInfo> mRuntimePermissionInfos; + // Cache uid -> packageNames + private SparseArray<String[]> mUidToPkg = new SparseArray<>(); + /** * All ops that need to be flipped to allow. * - * @see #syncPackages + * @see #syncUids */ - private final @NonNull ArrayList<OpToChange> mOpsToAllow = new ArrayList<>(); + private final @NonNull ArraySet<OpToChange> mOpsToAllow = new ArraySet<>(); /** * All ops that need to be flipped to ignore. * - * @see #syncPackages + * @see #syncUids */ - private final @NonNull ArrayList<OpToChange> mOpsToIgnore = new ArrayList<>(); + private final @NonNull ArraySet<OpToChange> mOpsToIgnore = new ArraySet<>(); /** * All ops that need to be flipped to ignore if not allowed. * * Currently, only used by soft restricted permissions logic. * - * @see #syncPackages + * @see #syncUids */ - private final @NonNull ArrayList<OpToChange> mOpsToIgnoreIfNotAllowed = new ArrayList<>(); + private final @NonNull ArraySet<OpToChange> mOpsToIgnoreIfNotAllowed = new ArraySet<>(); /** * All ops that need to be flipped to foreground. * * Currently, only used by the foreground/background permissions logic. * - * @see #syncPackages + * @see #syncUids */ - private final @NonNull ArrayList<OpToChange> mOpsToForeground = new ArrayList<>(); + private final @NonNull ArraySet<OpToChange> mOpsToForeground = new ArraySet<>(); + + private @Nullable String[] getPackageNamesForUid(int uid) { + String[] pkgs = mUidToPkg.get(uid); + if (pkgs != null) { + return pkgs; + } + + pkgs = mPackageManager.getPackagesForUid(uid); + mUidToPkg.put(uid, pkgs); + return pkgs; + } PermissionToOpSynchroniser(@NonNull Context context) { mContext = context; @@ -449,11 +449,11 @@ public final class PermissionPolicyService extends SystemService { } /** - * Set app ops that were added in {@link #addPackage}. + * Set app ops that were added in {@link #addUid}. * * <p>This processes ops previously added by {@link #addAppOps(PackageInfo, String)} */ - private void syncPackages() { + private void syncUids() { // Remember which ops were already set. This makes sure that we always set the most // permissive mode if two OpChanges are scheduled. This can e.g. happen if two // permissions change the same op. See {@link #getSwitchOp}. @@ -461,42 +461,42 @@ public final class PermissionPolicyService extends SystemService { final int allowCount = mOpsToAllow.size(); for (int i = 0; i < allowCount; i++) { - final OpToChange op = mOpsToAllow.get(i); + final OpToChange op = mOpsToAllow.valueAt(i); - setUidModeAllowed(op.code, op.uid, op.packageName); + setUidModeAllowed(op.code, op.uid); alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); } final int foregroundCount = mOpsToForeground.size(); for (int i = 0; i < foregroundCount; i++) { - final OpToChange op = mOpsToForeground.get(i); + final OpToChange op = mOpsToForeground.valueAt(i); if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { continue; } - setUidModeForeground(op.code, op.uid, op.packageName); + setUidModeForeground(op.code, op.uid); alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); } final int ignoreCount = mOpsToIgnore.size(); for (int i = 0; i < ignoreCount; i++) { - final OpToChange op = mOpsToIgnore.get(i); + final OpToChange op = mOpsToIgnore.valueAt(i); if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { continue; } - setUidModeIgnored(op.code, op.uid, op.packageName); + setUidModeIgnored(op.code, op.uid); alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); } final int ignoreIfNotAllowedCount = mOpsToIgnoreIfNotAllowed.size(); for (int i = 0; i < ignoreIfNotAllowedCount; i++) { - final OpToChange op = mOpsToIgnoreIfNotAllowed.get(i); + final OpToChange op = mOpsToIgnoreIfNotAllowed.valueAt(i); if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { continue; } - boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid, op.packageName); + boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid); if (wasSet) { alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); } @@ -555,7 +555,7 @@ public final class PermissionPolicyService extends SystemService { } int uid = packageInfo.applicationInfo.uid; - OpToChange opToChange = new OpToChange(uid, packageName, appOpCode); + OpToChange opToChange = new OpToChange(uid, appOpCode); switch (appOpMode) { case MODE_ALLOWED: mOpsToAllow.add(opToChange); @@ -618,8 +618,7 @@ public final class PermissionPolicyService extends SystemService { } int uid = packageInfo.applicationInfo.uid; - String packageName = packageInfo.packageName; - OpToChange extraOpToChange = new OpToChange(uid, packageName, extraOpCode); + OpToChange extraOpToChange = new OpToChange(uid, extraOpCode); if (policy.mayAllowExtraAppOp()) { mOpsToAllow.add(extraOpToChange); } else { @@ -632,45 +631,56 @@ public final class PermissionPolicyService extends SystemService { } /** - * Add a package for {@link #syncPackages() processing} later. + * Add a Uid for {@link #syncUids() processing} later. * * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. * - * @param pkgName The package to add for later processing. + * @param uid The uid to add for later processing. */ - void addPackage(@NonNull String pkgName) { - final PackageInfo pkg; - try { - pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS); - } catch (NameNotFoundException e) { + void addUid(int uid) { + String[] pkgNames = getPackageNamesForUid(uid); + if (pkgNames == null) { return; } - if (pkg.requestedPermissions == null) { - return; - } + for (String pkgName : pkgNames) { + final PackageInfo pkg; + try { + pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS); + } catch (NameNotFoundException e) { + continue; + } + + if (pkg.requestedPermissions == null) { + continue; + } - for (String permission : pkg.requestedPermissions) { - addAppOps(pkg, permission); + for (String permission : pkg.requestedPermissions) { + addAppOps(pkg, permission); + } } } - private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) { - setUidMode(opCode, uid, MODE_ALLOWED, packageName); + private void setUidModeAllowed(int opCode, int uid) { + setUidMode(opCode, uid, MODE_ALLOWED); } - private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) { - setUidMode(opCode, uid, MODE_FOREGROUND, packageName); + private void setUidModeForeground(int opCode, int uid) { + setUidMode(opCode, uid, MODE_FOREGROUND); } - private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) { - setUidMode(opCode, uid, MODE_IGNORED, packageName); + private void setUidModeIgnored(int opCode, int uid) { + setUidMode(opCode, uid, MODE_IGNORED); } - private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid, - @NonNull String packageName) { + private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid) { + String[] pkgsOfUid = getPackageNamesForUid(uid); + if (ArrayUtils.isEmpty(pkgsOfUid)) { + return false; + } + final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( - opCode), uid, packageName); + opCode), uid, pkgsOfUid[0]); if (currentMode != MODE_ALLOWED) { if (currentMode != MODE_IGNORED) { mAppOpsManagerInternal.setUidModeIgnoringCallback(opCode, uid, MODE_IGNORED, @@ -681,20 +691,24 @@ public final class PermissionPolicyService extends SystemService { return false; } - private void setUidMode(int opCode, int uid, int mode, - @NonNull String packageName) { + private void setUidMode(int opCode, int uid, int mode) { + String[] pkgsOfUid = getPackageNamesForUid(uid); + if (ArrayUtils.isEmpty(pkgsOfUid)) { + return; + } + final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( - opCode), uid, packageName); + opCode), uid, pkgsOfUid[0]); if (oldMode != mode) { mAppOpsManagerInternal.setUidModeIgnoringCallback(opCode, uid, mode, mAppOpsCallback); final int newMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( - opCode), uid, packageName); + opCode), uid, pkgsOfUid[0]); if (newMode != mode) { // Work around incorrectly-set package mode. It never makes sense for app ops // related to runtime permissions, but can get in the way and we have to reset // it. - mAppOpsManagerInternal.setModeIgnoringCallback(opCode, uid, packageName, + mAppOpsManagerInternal.setModeIgnoringCallback(opCode, uid, pkgsOfUid[0], AppOpsManager.opToDefaultMode(opCode), mAppOpsCallback); } } @@ -702,14 +716,30 @@ public final class PermissionPolicyService extends SystemService { private class OpToChange { final int uid; - final @NonNull String packageName; final int code; - OpToChange(int uid, @NonNull String packageName, int code) { + OpToChange(int uid, int code) { this.uid = uid; - this.packageName = packageName; this.code = code; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + OpToChange other = (OpToChange) o; + return uid == other.uid && code == other.code; + } + + @Override + public int hashCode() { + return Objects.hash(uid, code); + } } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 87c91ef6b96c..b1db9d7889dd 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -79,11 +79,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS; -import static com.android.server.wm.TaskProto.FILLS_PARENT; -import static com.android.server.wm.TaskProto.SURFACE_HEIGHT; -import static com.android.server.wm.TaskProto.SURFACE_WIDTH; -import static com.android.server.wm.TaskProto.WINDOW_CONTAINER; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; @@ -125,7 +120,6 @@ import android.provider.Settings; import android.service.voice.IVoiceInteractionSession; import android.util.DisplayMetrics; import android.util.Slog; -import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; import android.view.ITaskOrganizer; import android.view.RemoteAnimationTarget; @@ -3195,12 +3189,16 @@ class Task extends WindowContainer<WindowContainer> { info.lastActiveTime = lastActiveTime; info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription()); info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode(); - info.resizeMode = mResizeMode; info.configuration.setTo(getConfiguration()); info.token = mRemoteToken; // Get's the first non-undefined activity type among this and children. Can't use // configuration.windowConfiguration because that would only be this level. info.topActivityType = getActivityType(); + + //TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child + // order changes. + final Task top = getTopMostTask(); + info.resizeMode = top != null ? top.mResizeMode : mResizeMode; } /** diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 096541f57ba5..0a0530c92a16 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -23,6 +23,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; +import static com.android.server.wm.WindowContainer.POSITION_TOP; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; @@ -47,6 +49,7 @@ import com.android.internal.util.function.pooled.PooledLambda; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.WeakHashMap; @@ -375,6 +378,45 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub } } + @Override + public List<RunningTaskInfo> getChildTasks(IWindowContainer parent) { + enforceStackPermission("getChildTasks()"); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + if (parent == null) { + throw new IllegalArgumentException("Can't get children of null parent"); + } + final WindowContainer container = WindowContainer.fromBinder(parent.asBinder()); + if (container == null) { + Slog.e(TAG, "Can't get children of " + parent + " because it is not valid."); + return null; + } + // For now, only support returning children of persistent root tasks (of which the + // only current implementation is TaskTile). + if (!(container instanceof TaskTile)) { + Slog.w(TAG, "Can only get children of root tasks created via createRootTask"); + return null; + } + ArrayList<RunningTaskInfo> out = new ArrayList<>(); + // Tiles aren't real parents, so we need to go through stacks on the display to + // ensure correct ordering. + final DisplayContent dc = container.getDisplayContent(); + for (int i = dc.getStackCount() - 1; i >= 0; --i) { + final ActivityStack as = dc.getStackAt(i); + if (as.getTile() == container) { + final RunningTaskInfo info = new RunningTaskInfo(); + as.fillTaskInfo(info); + out.add(info); + } + } + return out; + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private int sanitizeAndApplyChange(WindowContainer container, WindowContainerTransaction.Change change) { if (!(container instanceof Task)) { @@ -405,6 +447,54 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub return effects; } + private int sanitizeAndApplyHierarchyOp(WindowContainer container, + WindowContainerTransaction.HierarchyOp hop) { + if (!(container instanceof Task)) { + throw new IllegalArgumentException("Invalid container in hierarchy op"); + } + if (hop.isReparent()) { + // special case for tiles since they are "virtual" parents + if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) { + ActivityStack as = (ActivityStack) container; + TaskTile newParent = hop.getNewParent() == null ? null + : (TaskTile) WindowContainer.fromBinder(hop.getNewParent()); + if (as.getTile() != newParent) { + if (as.getTile() != null) { + as.getTile().removeChild(as); + } + if (newParent != null) { + if (!as.affectedBySplitScreenResize()) { + return 0; + } + newParent.addChild(as, POSITION_TOP); + } + } + if (hop.getToTop()) { + as.getDisplay().positionStackAtTop(as, false /* includingParents */); + } else { + as.getDisplay().positionStackAtBottom(as); + } + } else if (container instanceof Task) { + throw new RuntimeException("Reparenting leaf Tasks is not supported now."); + } + } else { + // Ugh, of course ActivityStack has its own special reorder logic... + if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) { + ActivityStack as = (ActivityStack) container; + if (hop.getToTop()) { + as.getDisplay().positionStackAtTop(as, false /* includingParents */); + } else { + as.getDisplay().positionStackAtBottom(as); + } + } else { + container.getParent().positionChildAt( + hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM, + container, false /* includingParents */); + } + } + return TRANSACT_EFFECTS_LIFECYCLE; + } + private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask, int windowMask, Configuration config) { if ((container instanceof ActivityStack) @@ -470,8 +560,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub while (entries.hasNext()) { final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next(); - final WindowContainer wc = WindowContainer.RemoteToken.fromBinder( - entry.getKey()).getContainer(); + final WindowContainer wc = WindowContainer.fromBinder(entry.getKey()); int containerEffect = applyWindowContainerChange(wc, entry.getValue()); effects |= containerEffect; @@ -484,6 +573,13 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub mBLASTSyncEngine.addToSyncSet(syncId, wc); } } + // Hierarchy changes + final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps(); + for (int i = 0, n = hops.size(); i < n; ++i) { + final WindowContainerTransaction.HierarchyOp hop = hops.get(i); + final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); + effects |= sanitizeAndApplyHierarchyOp(wc, hop); + } if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { // Already calls ensureActivityConfig mService.mRootWindowContainer.ensureActivitiesVisible( diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 9acb660967cb..504aa2dc7b4c 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2296,6 +2296,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return mRemoteToken; } + static WindowContainer fromBinder(IBinder binder) { + return RemoteToken.fromBinder(binder).getContainer(); + } + static class RemoteToken extends IWindowContainer.Stub { final WeakReference<WindowContainer> mWeakRef; diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 812bc438246f..49c7e0a3b242 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -13,7 +13,6 @@ cc_library_static { ], srcs: [ - ":graphicsstats_proto", ":lib_alarmManagerService_native", "BroadcastRadio/JavaRef.cpp", "BroadcastRadio/NativeCallbackThread.cpp", @@ -53,7 +52,6 @@ cc_library_static { "com_android_server_UsbHostManager.cpp", "com_android_server_VibratorService.cpp", "com_android_server_PersistentDataBlockService.cpp", - "com_android_server_GraphicsStatsService.cpp", "com_android_server_am_CachedAppOptimizer.cpp", "com_android_server_am_LowMemDetector.cpp", "com_android_server_incremental_IncrementalManagerService.cpp", @@ -107,8 +105,6 @@ cc_defaults { "libinputflinger", "libinputflinger_base", "libinputservice", - "libprotobuf-cpp-lite", - "libprotoutil", "libstatshidl", "libstatspull", "libstatssocket", diff --git a/services/core/jni/com_android_server_GraphicsStatsService.cpp b/services/core/jni/com_android_server_GraphicsStatsService.cpp deleted file mode 100644 index aa7067ee7509..000000000000 --- a/services/core/jni/com_android_server_GraphicsStatsService.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#define LOG_TAG "GraphicsStatsService" - -#include <jni.h> -#include <log/log.h> -#include <nativehelper/JNIHelp.h> -#include <nativehelper/ScopedPrimitiveArray.h> -#include <nativehelper/ScopedUtfChars.h> -#include <JankTracker.h> -#include <service/GraphicsStatsService.h> -#include <stats_pull_atom_callback.h> -#include <stats_event.h> -#include <statslog.h> -#include <google/protobuf/io/zero_copy_stream_impl_lite.h> -#include <android/util/ProtoOutputStream.h> -#include "android/graphics/Utils.h" -#include "core_jni_helpers.h" -#include "protos/graphicsstats.pb.h" -#include <cstring> -#include <memory> - -namespace android { - -using namespace android::uirenderer; - -static jint getAshmemSize(JNIEnv*, jobject) { - return sizeof(ProfileData); -} - -static jlong createDump(JNIEnv*, jobject, jint fd, jboolean isProto) { - GraphicsStatsService::Dump* dump = GraphicsStatsService::createDump(fd, isProto - ? GraphicsStatsService::DumpType::Protobuf : GraphicsStatsService::DumpType::Text); - return reinterpret_cast<jlong>(dump); -} - -static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage, - jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) { - std::string path; - const ProfileData* data = nullptr; - LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null"); - ScopedByteArrayRO buffer{env}; - if (jdata != nullptr) { - buffer.reset(jdata); - LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData), - "Buffer size %zu doesn't match expected %zu!", buffer.size(), sizeof(ProfileData)); - data = reinterpret_cast<const ProfileData*>(buffer.get()); - } - if (jpath != nullptr) { - ScopedUtfChars pathChars(env, jpath); - LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars"); - path.assign(pathChars.c_str(), pathChars.size()); - } - ScopedUtfChars packageChars(env, jpackage); - LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(), "Failed to get path chars"); - GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr); - LOG_ALWAYS_FATAL_IF(!dump, "null passed for dump pointer"); - - const std::string package(packageChars.c_str(), packageChars.size()); - GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime, data); -} - -static void addFileToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath) { - ScopedUtfChars pathChars(env, jpath); - LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars"); - const std::string path(pathChars.c_str(), pathChars.size()); - GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr); - GraphicsStatsService::addToDump(dump, path); -} - -static void finishDump(JNIEnv*, jobject, jlong dumpPtr) { - GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr); - GraphicsStatsService::finishDump(dump); -} - -static jlong finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr) { - GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr); - std::vector<uint8_t>* result = new std::vector<uint8_t>(); - GraphicsStatsService::finishDumpInMemory(dump, - [](void* buffer, int bufferOffset, int bufferSize, int totalSize, void* param1, void* param2) { - std::vector<uint8_t>* outBuffer = reinterpret_cast<std::vector<uint8_t>*>(param2); - if (outBuffer->size() < totalSize) { - outBuffer->resize(totalSize); - } - std::memcpy(outBuffer->data() + bufferOffset, buffer, bufferSize); - }, env, result); - return reinterpret_cast<jlong>(result); -} - -static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpackage, - jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) { - ScopedByteArrayRO buffer(env, jdata); - LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData), - "Buffer size %zu doesn't match expected %zu!", buffer.size(), sizeof(ProfileData)); - ScopedUtfChars pathChars(env, jpath); - LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars"); - ScopedUtfChars packageChars(env, jpackage); - LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(), "Failed to get path chars"); - - const std::string path(pathChars.c_str(), pathChars.size()); - const std::string package(packageChars.c_str(), packageChars.size()); - const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer.get()); - GraphicsStatsService::saveBuffer(path, package, versionCode, startTime, endTime, data); -} - -static jobject gGraphicsStatsServiceObject = nullptr; -static jmethodID gGraphicsStatsService_pullGraphicsStatsMethodID; - -static JNIEnv* getJNIEnv() { - JavaVM* vm = AndroidRuntime::getJavaVM(); - JNIEnv* env = nullptr; - if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { - if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) { - LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!"); - } - } - return env; -} - -using namespace google::protobuf; - -// Field ids taken from FrameTimingHistogram message in atoms.proto -#define TIME_MILLIS_BUCKETS_FIELD_NUMBER 1 -#define FRAME_COUNTS_FIELD_NUMBER 2 - -static void writeCpuHistogram(AStatsEvent* event, - const uirenderer::protos::GraphicsStatsProto& stat) { - util::ProtoOutputStream proto; - for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) { - auto& bucket = stat.histogram(bucketIndex); - proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED | - TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */, - (int)bucket.render_millis()); - } - for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) { - auto& bucket = stat.histogram(bucketIndex); - proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED | - FRAME_COUNTS_FIELD_NUMBER /* field id */, - (long long)bucket.frame_count()); - } - std::vector<uint8_t> outVector; - proto.serializeToVector(&outVector); - AStatsEvent_writeByteArray(event, outVector.data(), outVector.size()); -} - -static void writeGpuHistogram(AStatsEvent* event, - const uirenderer::protos::GraphicsStatsProto& stat) { - util::ProtoOutputStream proto; - for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) { - auto& bucket = stat.gpu_histogram(bucketIndex); - proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED | - TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */, - (int)bucket.render_millis()); - } - for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) { - auto& bucket = stat.gpu_histogram(bucketIndex); - proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED | - FRAME_COUNTS_FIELD_NUMBER /* field id */, - (long long)bucket.frame_count()); - } - std::vector<uint8_t> outVector; - proto.serializeToVector(&outVector); - AStatsEvent_writeByteArray(event, outVector.data(), outVector.size()); -} - -// graphicsStatsPullCallback is invoked by statsd service to pull GRAPHICS_STATS atom. -static AStatsManager_PullAtomCallbackReturn graphicsStatsPullCallback(int32_t atom_tag, - AStatsEventList* data, - void* cookie) { - JNIEnv* env = getJNIEnv(); - if (!env) { - return false; - } - if (gGraphicsStatsServiceObject == nullptr) { - ALOGE("Failed to get graphicsstats service"); - return AStatsManager_PULL_SKIP; - } - - for (bool lastFullDay : {true, false}) { - jlong jdata = (jlong) env->CallLongMethod( - gGraphicsStatsServiceObject, - gGraphicsStatsService_pullGraphicsStatsMethodID, - (jboolean)(lastFullDay ? JNI_TRUE : JNI_FALSE)); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - ALOGE("Failed to invoke graphicsstats service"); - return AStatsManager_PULL_SKIP; - } - if (!jdata) { - // null means data is not available for that day. - continue; - } - android::uirenderer::protos::GraphicsStatsServiceDumpProto serviceDump; - std::vector<uint8_t>* buffer = reinterpret_cast<std::vector<uint8_t>*>(jdata); - std::unique_ptr<std::vector<uint8_t>> bufferRelease(buffer); - int dataSize = buffer->size(); - if (!dataSize) { - // Data is not available for that day. - continue; - } - io::ArrayInputStream input{buffer->data(), dataSize}; - bool success = serviceDump.ParseFromZeroCopyStream(&input); - if (!success) { - ALOGW("Parse failed on GraphicsStatsPuller error='%s' dataSize='%d'", - serviceDump.InitializationErrorString().c_str(), dataSize); - return AStatsManager_PULL_SKIP; - } - - for (int stat_index = 0; stat_index < serviceDump.stats_size(); stat_index++) { - auto& stat = serviceDump.stats(stat_index); - AStatsEvent* event = AStatsEventList_addStatsEvent(data); - AStatsEvent_setAtomId(event, android::util::GRAPHICS_STATS); - AStatsEvent_writeString(event, stat.package_name().c_str()); - AStatsEvent_writeInt64(event, (int64_t)stat.version_code()); - AStatsEvent_writeInt64(event, (int64_t)stat.stats_start()); - AStatsEvent_writeInt64(event, (int64_t)stat.stats_end()); - AStatsEvent_writeInt32(event, (int32_t)stat.pipeline()); - AStatsEvent_writeInt32(event, (int32_t)stat.summary().total_frames()); - AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_vsync_count()); - AStatsEvent_writeInt32(event, (int32_t)stat.summary().high_input_latency_count()); - AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_ui_thread_count()); - AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_bitmap_upload_count()); - AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_draw_count()); - AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_deadline_count()); - writeCpuHistogram(event, stat); - writeGpuHistogram(event, stat); - // TODO: fill in UI mainline module version, when the feature is available. - AStatsEvent_writeInt64(event, (int64_t)0); - AStatsEvent_writeBool(event, !lastFullDay); - AStatsEvent_build(event); - } - } - return AStatsManager_PULL_SUCCESS; -} - -// Register a puller for GRAPHICS_STATS atom with the statsd service. -static void nativeInit(JNIEnv* env, jobject javaObject) { - gGraphicsStatsServiceObject = env->NewGlobalRef(javaObject); - AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain(); - AStatsManager_PullAtomMetadata_setCoolDownNs(metadata, 10 * 1000000); // 10 milliseconds - AStatsManager_PullAtomMetadata_setTimeoutNs(metadata, 2 * NS_PER_SEC); // 2 seconds - - AStatsManager_registerPullAtomCallback(android::util::GRAPHICS_STATS, - &graphicsStatsPullCallback, metadata, nullptr); - - AStatsManager_PullAtomMetadata_release(metadata); -} - -static void nativeDestructor(JNIEnv* env, jobject javaObject) { - AStatsManager_unregisterPullAtomCallback(android::util::GRAPHICS_STATS); - env->DeleteGlobalRef(gGraphicsStatsServiceObject); - gGraphicsStatsServiceObject = nullptr; -} - -static const JNINativeMethod sMethods[] = { - { "nGetAshmemSize", "()I", (void*) getAshmemSize }, - { "nCreateDump", "(IZ)J", (void*) createDump }, - { "nAddToDump", "(JLjava/lang/String;Ljava/lang/String;JJJ[B)V", (void*) addToDump }, - { "nAddToDump", "(JLjava/lang/String;)V", (void*) addFileToDump }, - { "nFinishDump", "(J)V", (void*) finishDump }, - { "nFinishDumpInMemory", "(J)J", (void*) finishDumpInMemory }, - { "nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;JJJ[B)V", (void*) saveBuffer }, - { "nativeInit", "()V", (void*) nativeInit }, - { "nativeDestructor", "()V", (void*)nativeDestructor } -}; - -int register_android_server_GraphicsStatsService(JNIEnv* env) -{ - jclass graphicsStatsService_class = FindClassOrDie(env, - "com/android/server/GraphicsStatsService"); - gGraphicsStatsService_pullGraphicsStatsMethodID = GetMethodIDOrDie(env, - graphicsStatsService_class, "pullGraphicsStats", "(Z)J"); - return jniRegisterNativeMethods(env, "com/android/server/GraphicsStatsService", - sMethods, NELEM(sMethods)); -} - -} // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 1202ad33996d..c1864945f921 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -49,7 +49,7 @@ int register_android_server_PersistentDataBlockService(JNIEnv* env); int register_android_server_Watchdog(JNIEnv* env); int register_android_server_HardwarePropertiesManagerService(JNIEnv* env); int register_android_server_SyntheticPasswordManager(JNIEnv* env); -int register_android_server_GraphicsStatsService(JNIEnv* env); +int register_android_graphics_GraphicsStatsService(JNIEnv* env); int register_android_hardware_display_DisplayViewport(JNIEnv* env); int register_android_server_net_NetworkStatsFactory(JNIEnv* env); int register_android_server_net_NetworkStatsService(JNIEnv* env); @@ -102,7 +102,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_HardwarePropertiesManagerService(env); register_android_server_storage_AppFuse(env); register_android_server_SyntheticPasswordManager(env); - register_android_server_GraphicsStatsService(env); + register_android_graphics_GraphicsStatsService(env); register_android_hardware_display_DisplayViewport(env); register_android_server_net_NetworkStatsFactory(env); register_android_server_net_NetworkStatsService(env); diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp index 0941831f5299..b2c316a25e7f 100644 --- a/services/incremental/BinderIncrementalService.cpp +++ b/services/incremental/BinderIncrementalService.cpp @@ -16,6 +16,7 @@ #include "BinderIncrementalService.h" +#include <android-base/logging.h> #include <binder/IResultReceiver.h> #include <binder/PermissionCache.h> #include <incfs.h> @@ -24,7 +25,6 @@ #include "jni.h" #include "nativehelper/JNIHelp.h" #include "path.h" -#include <android-base/logging.h> using namespace std::literals; using namespace android::incremental; @@ -277,6 +277,13 @@ binder::Status BinderIncrementalService::startLoading(int32_t storageId, bool* _ return ok(); } +binder::Status BinderIncrementalService::configureNativeBinaries( + int32_t storageId, const std::string& apkFullPath, const std::string& libDirRelativePath, + const std::string& abi, bool* _aidl_return) { + *_aidl_return = mImpl.configureNativeBinaries(storageId, apkFullPath, libDirRelativePath, abi); + return ok(); +} + } // namespace android::os::incremental jlong Incremental_IncrementalService_Start() { diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h index 8a099776b54b..51d7de3d9adf 100644 --- a/services/incremental/BinderIncrementalService.h +++ b/services/incremental/BinderIncrementalService.h @@ -28,11 +28,11 @@ namespace android::os::incremental { class BinderIncrementalService : public BnIncrementalService, public BinderService<BinderIncrementalService> { public: - BinderIncrementalService(const sp<IServiceManager> &sm); + BinderIncrementalService(const sp<IServiceManager>& sm); - static BinderIncrementalService *start(); - static const char16_t *getServiceName() { return u"incremental_service"; } - status_t dump(int fd, const Vector<String16> &args) final; + static BinderIncrementalService* start(); + static const char16_t* getServiceName() { return u"incremental_service"; } + status_t dump(int fd, const Vector<String16>& args) final; void onSystemReady(); void onInvalidStorage(int mountId); @@ -70,6 +70,9 @@ public: std::vector<uint8_t>* _aidl_return) final; binder::Status startLoading(int32_t storageId, bool* _aidl_return) final; binder::Status deleteStorage(int32_t storageId) final; + binder::Status configureNativeBinaries(int32_t storageId, const std::string& apkFullPath, + const std::string& libDirRelativePath, + const std::string& abi, bool* _aidl_return) final; private: android::incremental::IncrementalService mImpl; diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index dbd97cfa039a..3b513774b615 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -60,6 +60,9 @@ struct Constants { static constexpr auto storagePrefix = "st"sv; static constexpr auto mountpointMdPrefix = ".mountpoint."sv; static constexpr auto infoMdName = ".info"sv; + static constexpr auto libDir = "lib"sv; + static constexpr auto libSuffix = ".so"sv; + static constexpr auto blockSize = 4096; }; static const Constants& constants() { @@ -259,16 +262,18 @@ IncrementalService::~IncrementalService() = default; inline const char* toString(TimePoint t) { using SystemClock = std::chrono::system_clock; - time_t time = SystemClock::to_time_t(SystemClock::now() + std::chrono::duration_cast<SystemClock::duration>(t - Clock::now())); + time_t time = SystemClock::to_time_t( + SystemClock::now() + + std::chrono::duration_cast<SystemClock::duration>(t - Clock::now())); return std::ctime(&time); } inline const char* toString(IncrementalService::BindKind kind) { switch (kind) { - case IncrementalService::BindKind::Temporary: - return "Temporary"; - case IncrementalService::BindKind::Permanent: - return "Permanent"; + case IncrementalService::BindKind::Temporary: + return "Temporary"; + case IncrementalService::BindKind::Permanent: + return "Permanent"; } } @@ -1124,6 +1129,122 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, return true; } +// Extract lib filse from zip, create new files in incfs and write data to them +bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath, + std::string_view libDirRelativePath, + std::string_view abi) { + const auto ifs = getIfs(storage); + // First prepare target directories if they don't exist yet + if (auto res = makeDirs(storage, libDirRelativePath, 0755)) { + LOG(ERROR) << "Failed to prepare target lib directory " << libDirRelativePath + << " errno: " << res; + return false; + } + + std::unique_ptr<ZipFileRO> zipFile(ZipFileRO::open(apkFullPath.data())); + if (!zipFile) { + LOG(ERROR) << "Failed to open zip file at " << apkFullPath; + return false; + } + void* cookie = nullptr; + const auto libFilePrefix = path::join(constants().libDir, abi); + if (!zipFile.get()->startIteration(&cookie, libFilePrefix.c_str() /* prefix */, + constants().libSuffix.data() /* suffix */)) { + LOG(ERROR) << "Failed to start zip iteration for " << apkFullPath; + return false; + } + ZipEntryRO entry = nullptr; + bool success = true; + while ((entry = zipFile.get()->nextEntry(cookie)) != nullptr) { + char fileName[PATH_MAX]; + if (zipFile.get()->getEntryFileName(entry, fileName, sizeof(fileName))) { + continue; + } + const auto libName = path::basename(fileName); + const auto targetLibPath = path::join(libDirRelativePath, libName); + const auto targetLibPathAbsolute = normalizePathToStorage(ifs, storage, targetLibPath); + // If the extract file already exists, skip + struct stat st; + if (stat(targetLibPathAbsolute.c_str(), &st) == 0) { + LOG(INFO) << "Native lib file already exists: " << targetLibPath + << "; skipping extraction"; + continue; + } + + uint32_t uncompressedLen; + if (!zipFile.get()->getEntryInfo(entry, nullptr, &uncompressedLen, nullptr, nullptr, + nullptr, nullptr)) { + LOG(ERROR) << "Failed to read native lib entry: " << fileName; + success = false; + break; + } + + // Create new lib file without signature info + incfs::NewFileParams libFileParams; + libFileParams.size = uncompressedLen; + libFileParams.verification.hashAlgorithm = INCFS_HASH_NONE; + // Metadata of the new lib file is its relative path + IncFsSpan libFileMetadata; + libFileMetadata.data = targetLibPath.c_str(); + libFileMetadata.size = targetLibPath.size(); + libFileParams.metadata = libFileMetadata; + incfs::FileId libFileId = idFromMetadata(targetLibPath); + if (auto res = makeFile(storage, targetLibPath, 0777, libFileId, libFileParams)) { + LOG(ERROR) << "Failed to make file for: " << targetLibPath << " errno: " << res; + success = false; + // If one lib file fails to be created, abort others as well + break; + } + + // Write extracted data to new file + std::vector<uint8_t> libData(uncompressedLen); + if (!zipFile.get()->uncompressEntry(entry, &libData[0], uncompressedLen)) { + LOG(ERROR) << "Failed to extract native lib zip entry: " << fileName; + success = false; + break; + } + android::base::unique_fd writeFd(mIncFs->openWrite(ifs->control, libFileId)); + if (writeFd < 0) { + LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd; + success = false; + break; + } + const int numBlocks = uncompressedLen / constants().blockSize + 1; + std::vector<IncFsDataBlock> instructions; + auto remainingData = std::span(libData); + for (int i = 0; i < numBlocks - 1; i++) { + auto inst = IncFsDataBlock{ + .fileFd = writeFd, + .pageIndex = static_cast<IncFsBlockIndex>(i), + .compression = INCFS_COMPRESSION_KIND_NONE, + .kind = INCFS_BLOCK_KIND_DATA, + .dataSize = static_cast<uint16_t>(constants().blockSize), + .data = reinterpret_cast<const char*>(remainingData.data()), + }; + instructions.push_back(inst); + remainingData = remainingData.subspan(constants().blockSize); + } + // Last block + auto inst = IncFsDataBlock{ + .fileFd = writeFd, + .pageIndex = static_cast<IncFsBlockIndex>(numBlocks - 1), + .compression = INCFS_COMPRESSION_KIND_NONE, + .kind = INCFS_BLOCK_KIND_DATA, + .dataSize = static_cast<uint16_t>(remainingData.size()), + .data = reinterpret_cast<const char*>(remainingData.data()), + }; + instructions.push_back(inst); + size_t res = mIncFs->writeBlocks(instructions); + if (res != instructions.size()) { + LOG(ERROR) << "Failed to write data into: " << targetLibPath; + success = false; + } + instructions.clear(); + } + zipFile.get()->endIteration(cookie); + return success; +} + binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId, int newStatus) { std::unique_lock l(incrementalService.mLock); diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index dec9f64f2084..2444ddecdb80 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -126,7 +126,8 @@ public: std::vector<std::string> listFiles(StorageId storage) const; bool startLoading(StorageId storage) const; - + bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath, + std::string_view libDirRelativePath, std::string_view abi); class IncrementalDataLoaderListener : public android::content::pm::BnDataLoaderStatusListener { public: IncrementalDataLoaderListener(IncrementalService& incrementalService) diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 036335ca9011..eef6c63d29c9 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -41,6 +41,7 @@ import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.database.sqlite.SQLiteCompatibilityWalFlags; import android.database.sqlite.SQLiteGlobal; +import android.graphics.GraphicsStatsService; import android.hardware.display.DisplayManagerInternal; import android.net.ConnectivityModuleConnector; import android.net.ITetheringConnector; diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java index bb97533b3222..b60ed3e8783f 100644 --- a/services/people/java/com/android/server/people/data/ConversationInfo.java +++ b/services/people/java/com/android/server/people/data/ConversationInfo.java @@ -35,7 +35,7 @@ import java.util.Objects; */ public class ConversationInfo { - private static final int FLAG_VIP = 1; + private static final int FLAG_IMPORTANT = 1; private static final int FLAG_NOTIFICATION_SILENCED = 1 << 1; @@ -50,7 +50,7 @@ public class ConversationInfo { private static final int FLAG_DEMOTED = 1 << 6; @IntDef(flag = true, prefix = {"FLAG_"}, value = { - FLAG_VIP, + FLAG_IMPORTANT, FLAG_NOTIFICATION_SILENCED, FLAG_BUBBLED, FLAG_PERSON_IMPORTANT, @@ -129,9 +129,9 @@ public class ConversationInfo { return hasShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED); } - /** Whether this conversation is marked as VIP by the user. */ - public boolean isVip() { - return hasConversationFlags(FLAG_VIP); + /** Whether this conversation is marked as important by the user. */ + public boolean isImportant() { + return hasConversationFlags(FLAG_IMPORTANT); } /** Whether the notifications for this conversation should be silenced. */ @@ -208,8 +208,8 @@ public class ConversationInfo { sb.append("]"); sb.append(", conversationFlags=0x").append(Integer.toHexString(mConversationFlags)); sb.append(" ["); - if (isVip()) { - sb.append("Vip"); + if (isImportant()) { + sb.append("Imp"); } if (isNotificationSilenced()) { sb.append("Sil"); @@ -221,7 +221,7 @@ public class ConversationInfo { sb.append("Dem"); } if (isPersonImportant()) { - sb.append("Imp"); + sb.append("PIm"); } if (isPersonBot()) { sb.append("Bot"); @@ -318,8 +318,8 @@ public class ConversationInfo { return this; } - Builder setVip(boolean value) { - return setConversationFlag(FLAG_VIP, value); + Builder setImportant(boolean value) { + return setConversationFlag(FLAG_IMPORTANT, value); } Builder setNotificationSilenced(boolean value) { diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java index 7fdcf42c6364..7a3ed5348d30 100644 --- a/services/people/java/com/android/server/people/data/DataManager.java +++ b/services/people/java/com/android/server/people/data/DataManager.java @@ -21,6 +21,8 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; import android.app.Person; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; @@ -157,8 +159,8 @@ public class DataManager { mNotificationListeners.put(userId, notificationListener); try { notificationListener.registerAsSystemService(mContext, - new ComponentName(PLATFORM_PACKAGE_NAME, getClass().getSimpleName()), - UserHandle.myUserId()); + new ComponentName(PLATFORM_PACKAGE_NAME, getClass().getCanonicalName()), + userId); } catch (RemoteException e) { // Should never occur for local calls. } @@ -571,6 +573,44 @@ public class DataManager { long currentTime = System.currentTimeMillis(); eventHistory.addEvent(new Event(currentTime, Event.TYPE_NOTIFICATION_OPENED)); } + + @Override + public void onNotificationChannelModified(String pkg, UserHandle user, + NotificationChannel channel, int modificationType) { + PackageData packageData = getPackage(pkg, user.getIdentifier()); + String shortcutId = channel.getConversationId(); + if (packageData == null || shortcutId == null) { + return; + } + ConversationStore conversationStore = packageData.getConversationStore(); + ConversationInfo conversationInfo = conversationStore.getConversation(shortcutId); + if (conversationInfo == null) { + return; + } + ConversationInfo.Builder builder = new ConversationInfo.Builder(conversationInfo); + switch (modificationType) { + case NOTIFICATION_CHANNEL_OR_GROUP_ADDED: + case NOTIFICATION_CHANNEL_OR_GROUP_UPDATED: + builder.setNotificationChannelId(channel.getId()); + builder.setImportant(channel.isImportantConversation()); + builder.setDemoted(channel.isDemoted()); + builder.setNotificationSilenced( + channel.getImportance() <= NotificationManager.IMPORTANCE_LOW); + builder.setBubbled(channel.canBubble()); + break; + case NOTIFICATION_CHANNEL_OR_GROUP_DELETED: + // If the notification channel is deleted, revert all the notification settings + // to the default value. + builder.setNotificationChannelId(null); + builder.setImportant(false); + builder.setDemoted(false); + builder.setNotificationSilenced(false); + builder.setBubbled(false); + break; + } + conversationStore.addOrUpdate(builder.build()); + // TODO: Cache the shortcut when a conversation's notification setting is changed. + } } /** diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java index 8d2a152dba83..6083ce34a3bd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java @@ -174,12 +174,12 @@ public class ApplicationExitInfoTest { final int app1ConnectiongGroup = 10; final int app1UidUser2 = 1010123; final int app1PidUser2 = 12347; - final int app1Pss1 = 34567; - final int app1Rss1 = 45678; - final int app1Pss2 = 34568; - final int app1Rss2 = 45679; - final int app1Pss3 = 34569; - final int app1Rss3 = 45680; + final long app1Pss1 = 34567; + final long app1Rss1 = 45678; + final long app1Pss2 = 34568; + final long app1Rss2 = 45679; + final long app1Pss3 = 34569; + final long app1Rss3 = 45680; final String app1ProcessName = "com.android.test.stub1:process"; final String app1PackageName = "com.android.test.stub1"; @@ -344,8 +344,8 @@ public class ApplicationExitInfoTest { // Case 4: Create a process from another package with kill from lmkd final int app2UidUser2 = 1010234; final int app2PidUser2 = 12348; - final int app2Pss1 = 54321; - final int app2Rss1 = 65432; + final long app2Pss1 = 54321; + final long app2Rss1 = 65432; final String app2ProcessName = "com.android.test.stub2:process"; final String app2PackageName = "com.android.test.stub2"; @@ -402,8 +402,8 @@ public class ApplicationExitInfoTest { final int app3UidUser2 = 1010345; final int app3PidUser2 = 12349; final int app3ConnectiongGroup = 4; - final int app3Pss1 = 54320; - final int app3Rss1 = 65430; + final long app3Pss1 = 54320; + final long app3Rss1 = 65430; final String app3ProcessName = "com.android.test.stub3:process"; final String app3PackageName = "com.android.test.stub3"; final String app3Description = "native crash"; @@ -529,8 +529,8 @@ public class ApplicationExitInfoTest { final int app3Uid = 10345; final int app3IsolatedUid = 99001; // it's an isolated process final int app3Pid = 12350; - final int app3Pss2 = 23232; - final int app3Rss2 = 32323; + final long app3Pss2 = 23232; + final long app3Rss2 = 32323; final String app3Description2 = "force close"; sleep(1); @@ -618,8 +618,8 @@ public class ApplicationExitInfoTest { sleep(1); final int app1IsolatedUidUser2 = 1099002; // isolated uid - final int app1Pss4 = 34343; - final int app1Rss4 = 43434; + final long app1Pss4 = 34343; + final long app1Rss4 = 43434; final long now8 = System.currentTimeMillis(); sigNum = OsConstants.SIGKILL; doReturn(new Pair<Long, Object>(now8, makeSignalStatus(sigNum))) @@ -673,8 +673,8 @@ public class ApplicationExitInfoTest { sleep(1); final int app1Pid2User2 = 56565; final int app1IsolatedUid2User2 = 1099003; // isolated uid - final int app1Pss5 = 34344; - final int app1Rss5 = 43435; + final long app1Pss5 = 34344; + final long app1Rss5 = 43435; final long now9 = System.currentTimeMillis(); sigNum = OsConstants.SIGKILL; doReturn(new Pair<Long, Object>(now9, makeSignalStatus(sigNum))) @@ -831,7 +831,7 @@ public class ApplicationExitInfoTest { } private ProcessRecord makeProcessRecord(int pid, int uid, int packageUid, Integer definingUid, - int connectionGroup, int procState, int pss, int rss, + int connectionGroup, int procState, long pss, long rss, String processName, String packageName) { ApplicationInfo ai = new ApplicationInfo(); ai.packageName = packageName; @@ -847,8 +847,8 @@ public class ApplicationExitInfoTest { app.connectionGroup = connectionGroup; app.setProcState = procState; app.lastMemInfo = spy(new Debug.MemoryInfo()); - doReturn(pss).when(app.lastMemInfo).getTotalPss(); - doReturn(rss).when(app.lastMemInfo).getTotalRss(); + doReturn((int) pss).when(app.lastMemInfo).getTotalPss(); + doReturn((int) rss).when(app.lastMemInfo).getTotalRss(); return app; } @@ -856,7 +856,7 @@ public class ApplicationExitInfoTest { Long timestamp, Integer pid, Integer uid, Integer packageUid, Integer definingUid, String processName, Integer connectionGroup, Integer reason, Integer subReason, Integer status, - Integer pss, Integer rss, Integer importance, String description) { + Long pss, Long rss, Integer importance, String description) { assertNotNull(info); if (timestamp != null) { @@ -892,10 +892,10 @@ public class ApplicationExitInfoTest { assertEquals(status.intValue(), info.getStatus()); } if (pss != null) { - assertEquals(pss.intValue(), info.getPss()); + assertEquals(pss.longValue(), info.getPss()); } if (rss != null) { - assertEquals(rss.intValue(), info.getRss()); + assertEquals(rss.longValue(), info.getRss()); } if (importance != null) { assertEquals(importance.intValue(), info.getImportance()); diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java index 16dde4203e91..1f147403d655 100644 --- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java @@ -43,6 +43,7 @@ import com.android.server.blob.BlobStoreManagerService.Injector; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -209,6 +210,7 @@ public class BlobStoreManagerServiceTest { verify(file3, never()).delete(); } + @Ignore @Test public void testHandleIdleMaintenance_deleteStaleSessions() throws Exception { // Setup sessions @@ -216,8 +218,8 @@ public class BlobStoreManagerServiceTest { doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS + 1000) .when(sessionFile1).lastModified(); final long sessionId1 = 342; - final BlobHandle blobHandle1 = mock(BlobHandle.class); - doReturn(System.currentTimeMillis() - 1000).when(blobHandle1).getExpiryTimeMillis(); + final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest1".getBytes(), + "label1", System.currentTimeMillis() - 1000, "tag1"); final BlobStoreSession session1 = createBlobStoreSessionMock(TEST_PKG1, TEST_UID1, sessionId1, sessionFile1, blobHandle1); mUserSessions.append(sessionId1, session1); @@ -226,8 +228,8 @@ public class BlobStoreManagerServiceTest { doReturn(System.currentTimeMillis() - 20000) .when(sessionFile2).lastModified(); final long sessionId2 = 4597; - final BlobHandle blobHandle2 = mock(BlobHandle.class); - doReturn(System.currentTimeMillis() + 20000).when(blobHandle2).getExpiryTimeMillis(); + final BlobHandle blobHandle2 = BlobHandle.createWithSha256("digest2".getBytes(), + "label2", System.currentTimeMillis() + 20000, "tag2"); final BlobStoreSession session2 = createBlobStoreSessionMock(TEST_PKG2, TEST_UID2, sessionId2, sessionFile2, blobHandle2); mUserSessions.append(sessionId2, session2); @@ -236,8 +238,8 @@ public class BlobStoreManagerServiceTest { doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS - 2000) .when(sessionFile3).lastModified(); final long sessionId3 = 9484; - final BlobHandle blobHandle3 = mock(BlobHandle.class); - doReturn(System.currentTimeMillis() + 30000).when(blobHandle3).getExpiryTimeMillis(); + final BlobHandle blobHandle3 = BlobHandle.createWithSha256("digest3".getBytes(), + "label3", System.currentTimeMillis() + 30000, "tag3"); final BlobStoreSession session3 = createBlobStoreSessionMock(TEST_PKG3, TEST_UID3, sessionId3, sessionFile3, blobHandle3); mUserSessions.append(sessionId3, session3); diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java index 05a9a80e262c..c0e7927a8d72 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java @@ -47,7 +47,7 @@ public final class ConversationInfoTest { .setContactPhoneNumber(PHONE_NUMBER) .setNotificationChannelId(NOTIFICATION_CHANNEL_ID) .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED) - .setVip(true) + .setImportant(true) .setNotificationSilenced(true) .setBubbled(true) .setDemoted(true) @@ -62,7 +62,7 @@ public final class ConversationInfoTest { assertEquals(PHONE_NUMBER, conversationInfo.getContactPhoneNumber()); assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId()); assertTrue(conversationInfo.isShortcutLongLived()); - assertTrue(conversationInfo.isVip()); + assertTrue(conversationInfo.isImportant()); assertTrue(conversationInfo.isNotificationSilenced()); assertTrue(conversationInfo.isBubbled()); assertTrue(conversationInfo.isDemoted()); @@ -83,7 +83,7 @@ public final class ConversationInfoTest { assertNull(conversationInfo.getContactPhoneNumber()); assertNull(conversationInfo.getNotificationChannelId()); assertFalse(conversationInfo.isShortcutLongLived()); - assertFalse(conversationInfo.isVip()); + assertFalse(conversationInfo.isImportant()); assertFalse(conversationInfo.isNotificationSilenced()); assertFalse(conversationInfo.isBubbled()); assertFalse(conversationInfo.isDemoted()); @@ -101,7 +101,7 @@ public final class ConversationInfoTest { .setContactPhoneNumber(PHONE_NUMBER) .setNotificationChannelId(NOTIFICATION_CHANNEL_ID) .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED) - .setVip(true) + .setImportant(true) .setNotificationSilenced(true) .setBubbled(true) .setPersonImportant(true) @@ -110,7 +110,7 @@ public final class ConversationInfoTest { .build(); ConversationInfo destination = new ConversationInfo.Builder(source) - .setVip(false) + .setImportant(false) .setContactStarred(false) .build(); @@ -120,7 +120,7 @@ public final class ConversationInfoTest { assertEquals(PHONE_NUMBER, destination.getContactPhoneNumber()); assertEquals(NOTIFICATION_CHANNEL_ID, destination.getNotificationChannelId()); assertTrue(destination.isShortcutLongLived()); - assertFalse(destination.isVip()); + assertFalse(destination.isImportant()); assertTrue(destination.isNotificationSilenced()); assertTrue(destination.isBubbled()); assertTrue(destination.isPersonImportant()); diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java index bbcb54ef8d3e..331ad5972fc1 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java @@ -167,7 +167,7 @@ public final class ConversationStoreTest { .setContactPhoneNumber(phoneNumber) .setNotificationChannelId(notificationChannelId) .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED) - .setVip(true) + .setImportant(true) .setBubbled(true) .build(); } diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java index ad5c57dd11bc..498d8886eec3 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java @@ -16,10 +16,15 @@ package com.android.server.people.data; +import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED; +import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED; +import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED; + import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -33,6 +38,8 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; import android.app.Person; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; @@ -88,6 +95,7 @@ public final class DataManagerTest { private static final String TEST_SHORTCUT_ID = "sc"; private static final String CONTACT_URI = "content://com.android.contacts/contacts/lookup/123"; private static final String PHONE_NUMBER = "+1234567890"; + private static final String NOTIFICATION_CHANNEL_ID = "test : sc"; private static final long MILLIS_PER_MINUTE = 1000L * 60L; @Mock private Context mContext; @@ -103,6 +111,7 @@ public final class DataManagerTest { @Mock private StatusBarNotification mStatusBarNotification; @Mock private Notification mNotification; + private NotificationChannel mNotificationChannel; private DataManager mDataManager; private int mCallingUserId; private TestInjector mInjector; @@ -152,6 +161,10 @@ public final class DataManagerTest { when(mStatusBarNotification.getUser()).thenReturn(UserHandle.of(USER_ID_PRIMARY)); when(mNotification.getShortcutId()).thenReturn(TEST_SHORTCUT_ID); + mNotificationChannel = new NotificationChannel( + NOTIFICATION_CHANNEL_ID, "test channel", NotificationManager.IMPORTANCE_DEFAULT); + mNotificationChannel.setConversationId("test", TEST_SHORTCUT_ID); + mCallingUserId = USER_ID_PRIMARY; mInjector = new TestInjector(); @@ -284,9 +297,8 @@ public final class DataManagerTest { } @Test - public void testNotificationListener() { + public void testNotificationOpened() { mDataManager.onUserUnlocked(USER_ID_PRIMARY); - mDataManager.onUserUnlocked(USER_ID_SECONDARY); ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, buildPerson()); @@ -308,6 +320,83 @@ public final class DataManagerTest { } @Test + public void testNotificationChannelCreated() { + mDataManager.onUserUnlocked(USER_ID_PRIMARY); + mDataManager.onUserUnlocked(USER_ID_SECONDARY); + + ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, + buildPerson()); + mDataManager.onShortcutAddedOrUpdated(shortcut); + + NotificationListenerService listenerService = + mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY); + listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY), + mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_ADDED); + + ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY) + .getConversationStore() + .getConversation(TEST_SHORTCUT_ID); + assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId()); + assertFalse(conversationInfo.isImportant()); + assertFalse(conversationInfo.isNotificationSilenced()); + assertFalse(conversationInfo.isDemoted()); + } + + @Test + public void testNotificationChannelModified() { + mNotificationChannel.setImportantConversation(true); + + mDataManager.onUserUnlocked(USER_ID_PRIMARY); + mDataManager.onUserUnlocked(USER_ID_SECONDARY); + + ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, + buildPerson()); + mDataManager.onShortcutAddedOrUpdated(shortcut); + + NotificationListenerService listenerService = + mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY); + listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY), + mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED); + + ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY) + .getConversationStore() + .getConversation(TEST_SHORTCUT_ID); + assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId()); + assertTrue(conversationInfo.isImportant()); + assertFalse(conversationInfo.isNotificationSilenced()); + assertFalse(conversationInfo.isDemoted()); + } + + @Test + public void testNotificationChannelDeleted() { + mDataManager.onUserUnlocked(USER_ID_PRIMARY); + mDataManager.onUserUnlocked(USER_ID_SECONDARY); + + ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, + buildPerson()); + mDataManager.onShortcutAddedOrUpdated(shortcut); + + NotificationListenerService listenerService = + mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY); + listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY), + mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_ADDED); + ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY) + .getConversationStore() + .getConversation(TEST_SHORTCUT_ID); + assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId()); + + listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY), + mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_DELETED); + conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY) + .getConversationStore() + .getConversation(TEST_SHORTCUT_ID); + assertNull(conversationInfo.getNotificationChannelId()); + assertFalse(conversationInfo.isImportant()); + assertFalse(conversationInfo.isNotificationSilenced()); + assertFalse(conversationInfo.isDemoted()); + } + + @Test public void testCallLogContentObserver() { mDataManager.onUserUnlocked(USER_ID_PRIMARY); mDataManager.onUserUnlocked(USER_ID_SECONDARY); diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 3d190be8888b..77f842aa503f 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -556,6 +556,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { void injectRestoreCallingIdentity(long token) { mInjectedCallingUid = (int) token; } + + @Override + boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) { + return true; + } } protected class LauncherAppsTestable extends LauncherApps { @@ -1617,6 +1622,22 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } /** + * Make a long lived shortcut with an ID. + */ + protected ShortcutInfo makeLongLivedShortcut(String id) { + final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext, id) + .setActivity(new ComponentName(mClientContext.getPackageName(), "main")) + .setShortLabel("title-" + id) + .setIntent(makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class)) + .setLongLived(true); + final ShortcutInfo s = b.build(); + + s.setTimestamp(mInjectedCurrentTimeMillis); // HACK + + return s; + } + + /** * Make an intent. */ protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) { diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 63da5fbab122..f03670843f3a 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -1240,7 +1240,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { assertTrue(mManager.setDynamicShortcuts(list( - makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3")))); + makeLongLivedShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3")))); }); // Pin 2 and 3 @@ -1250,9 +1250,12 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { }); // Cache 1 and 2 + runWithCaller(LAUNCHER_1, USER_0, () -> { + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), + HANDLE_USER_0); + }); + setCaller(CALLING_PACKAGE_1); - getCallerShortcut("s1").setCached(); - getCallerShortcut("s2").setCached(); // Get manifest shortcuts assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_MANIFEST), @@ -1315,8 +1318,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { public void testCachedShortcuts() { runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { - assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"), makeShortcut("s2"), - makeShortcut("s3"), makeShortcut("s4")))); + assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"), + makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3"), + makeLongLivedShortcut("s4")))); }); // Pin s2 @@ -1325,11 +1329,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { HANDLE_USER_0); }); - // Cache 2, 3 and 4 + // Cache some, but non long lived shortcuts will be ignored. + runWithCaller(LAUNCHER_1, USER_0, () -> { + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s4"), + HANDLE_USER_0); + }); + setCaller(CALLING_PACKAGE_1); - getCallerShortcut("s2").setCached(); - getCallerShortcut("s3").setCached(); - getCallerShortcut("s4").setCached(); // Get dynamic shortcuts assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC), @@ -1339,27 +1345,37 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "s2"); // Get cached shortcuts assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), - "s2", "s3", "s4"); + "s2", "s4"); // Remove a dynamic cached shortcut - mManager.removeDynamicShortcuts(list("s3")); + mManager.removeDynamicShortcuts(list("s4")); assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC), - "s1", "s2", "s4"); + "s1", "s2", "s3"); assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), - "s2", "s3", "s4"); + "s2", "s4"); - // Remove dynamic cached long lived shortcuts - mManager.removeLongLivedShortcuts(list("s3", "s4")); - assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC), - "s1", "s2"); + // uncache a non-dynamic shortcut. Should be removed. + runWithCaller(LAUNCHER_1, USER_0, () -> { + mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s4"), + HANDLE_USER_0); + }); assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s2"); + // Cache another shortcut + runWithCaller(LAUNCHER_1, USER_0, () -> { + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s3"), + HANDLE_USER_0); + }); + assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), + "s2", "s3"); + // Remove a dynamic cached pinned long lived shortcut mManager.removeLongLivedShortcuts(list("s2")); assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC), - "s1"); - assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED)); + "s1", "s3"); + assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), + "s3"); assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_PINNED), "s2"); } @@ -1371,7 +1387,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Set up shortcuts. setCaller(CALLING_PACKAGE_1); - final ShortcutInfo s1_1 = makeShortcut("s1"); + final ShortcutInfo s1_1 = makeLongLivedShortcut("s1"); final ShortcutInfo s1_2 = makeShortcutWithLocusId("s2", makeLocusId("l1")); assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2))); @@ -1395,6 +1411,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { setCaller(CALLING_PACKAGE_3); final ShortcutInfo s3_2 = makeShortcutWithLocusId("s3", makeLocusId("l2")); + s3_2.setLongLived(); + assertTrue(mManager.setDynamicShortcuts(list(s3_2))); getCallerShortcut("s3").setTimestamp(START_TIME + 5000); @@ -1535,26 +1553,20 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // TODO More tests: pinned but dynamic. - // Cache some shortcuts - setCaller(CALLING_PACKAGE_1); - getCallerShortcut("s1").setCached(); - - setCaller(CALLING_PACKAGE_2); - getCallerShortcut("s4").setCached(); - - setCaller(CALLING_PACKAGE_3); - getCallerShortcut("s3").setCached(); - setCaller(LAUNCHER_1); + // Cache some shortcuts. Only long lived shortcuts can get cached. + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), getCallingUser()); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_3, list("s3"), getCallingUser()); + // Cached ones only assertShortcutIds(assertAllNotKeyFieldsOnly( mLauncherApps.getShortcuts(buildQuery( - /* time =*/ 0, CALLING_PACKAGE_2, + /* time =*/ 0, CALLING_PACKAGE_3, /* activity =*/ null, ShortcutQuery.FLAG_MATCH_CACHED), getCallingUser())), - "s4"); + "s3"); // All packages. assertShortcutIds(assertAllNotKeyFieldsOnly( @@ -1563,7 +1575,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* activity =*/ null, ShortcutQuery.FLAG_MATCH_CACHED), getCallingUser())), - "s1", "s4", "s3"); + "s1", "s3"); assertExpectException( IllegalArgumentException.class, "package name must also be set", () -> { @@ -1581,7 +1593,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { /* activity =*/ null, ShortcutQuery.FLAG_MATCH_CACHED), getCallingUser())), - "s1", "s4", "s3"); + "s1", "s3"); } public void testGetShortcuts_shortcutKinds() throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java index fde0ddffa365..4d0481be20b3 100644 --- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java @@ -144,6 +144,40 @@ public class SystemConfigTest { assertEquals("Incorrect blacklist", expectedBlack, actualBlack); } + @Test + public void testComponentOverride() throws Exception { + final String contents = + "<permissions>" + + " <component-override package=\"com.android.package1\">\n" + + " <component class=\"com.android.package1.Full\" enabled=\"true\"/>" + + " <component class=\".Relative\" enabled=\"false\" />\n" + + " </component-override>" + + " <component-override package=\"com.android.package2\" >\n" + + " <component class=\"com.android.package3.Relative2\" enabled=\"yes\" />\n" + + " </component-override>\n" + + "</permissions>"; + + final File folder = createTempSubfolder("folder"); + createTempFile(folder, "component-override.xml", contents); + + mSysConfig.readPermissions(folder, /* No permission needed anyway */ 0); + + final ArrayMap<String, Boolean> packageOneExpected = new ArrayMap<>(); + packageOneExpected.put("com.android.package1.Full", true); + packageOneExpected.put("com.android.package1.Relative", false); + + final ArrayMap<String, Boolean> packageTwoExpected = new ArrayMap<>(); + packageTwoExpected.put("com.android.package3.Relative2", true); + + final Map<String, Boolean> packageOne = mSysConfig.getComponentsEnabledStates( + "com.android.package1"); + assertEquals(packageOneExpected, packageOne); + + final Map<String, Boolean> packageTwo = mSysConfig.getComponentsEnabledStates( + "com.android.package2"); + assertEquals(packageTwoExpected, packageTwo); + } + /** * Creates folderName/fileName in the mTemporaryFolder and fills it with the contents. * @param folderName subdirectory of mTemporaryFolder to put the file, creating if needed diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java index 5b5ad877081c..cbb760a7a871 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java @@ -44,6 +44,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.internal.matchers.Not; import java.io.File; import java.util.ArrayList; @@ -239,6 +240,52 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase { verify(af2, never()).openRead(); } + @Test + public void testRemoveNotificationRunnable() throws Exception { + NotificationHistory nh = mock(NotificationHistory.class); + NotificationHistoryDatabase.RemoveNotificationRunnable rnr = + mDataBase.new RemoveNotificationRunnable("pkg", 123); + rnr.setNotificationHistory(nh); + + AtomicFile af = mock(AtomicFile.class); + when(af.getBaseFile()).thenReturn(new File(mRootDir, "af")); + mDataBase.mHistoryFiles.addLast(af); + + when(nh.removeNotificationFromWrite("pkg", 123)).thenReturn(true); + + mDataBase.mBuffer = mock(NotificationHistory.class); + + rnr.run(); + + verify(mDataBase.mBuffer).removeNotificationFromWrite("pkg", 123); + verify(af).openRead(); + verify(nh).removeNotificationFromWrite("pkg", 123); + verify(af).startWrite(); + } + + @Test + public void testRemoveNotificationRunnable_noChanges() throws Exception { + NotificationHistory nh = mock(NotificationHistory.class); + NotificationHistoryDatabase.RemoveNotificationRunnable rnr = + mDataBase.new RemoveNotificationRunnable("pkg", 123); + rnr.setNotificationHistory(nh); + + AtomicFile af = mock(AtomicFile.class); + when(af.getBaseFile()).thenReturn(new File(mRootDir, "af")); + mDataBase.mHistoryFiles.addLast(af); + + when(nh.removeNotificationFromWrite("pkg", 123)).thenReturn(false); + + mDataBase.mBuffer = mock(NotificationHistory.class); + + rnr.run(); + + verify(mDataBase.mBuffer).removeNotificationFromWrite("pkg", 123); + verify(af).openRead(); + verify(nh).removeNotificationFromWrite("pkg", 123); + verify(af, never()).startWrite(); + } + private class TestFileAttrProvider implements NotificationHistoryDatabase.FileAttrProvider { public Map<File, Long> creationDates = new HashMap<>(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java index b5eb1bf31848..2c548be185c9 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java @@ -289,6 +289,20 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase { } @Test + public void testDeleteNotificationHistoryItem_userUnlocked() { + String pkg = "pkg"; + long time = 235; + NotificationHistoryDatabase userHistory = mock(NotificationHistoryDatabase.class); + + mHistoryManager.onUserUnlocked(USER_SYSTEM); + mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistory); + + mHistoryManager.deleteNotificationHistoryItem(pkg, 1, time); + + verify(userHistory, times(1)).deleteNotificationHistoryItem(pkg, time); + } + + @Test public void testTriggerWriteToDisk() { NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class); NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java index 7172a1b14244..f7aa3cc9e52c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java @@ -29,10 +29,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -45,8 +45,10 @@ import android.app.ActivityManager.StackInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; +import android.os.IBinder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; +import android.util.ArrayMap; import android.view.Display; import android.view.ITaskOrganizer; import android.view.IWindowContainer; @@ -357,6 +359,78 @@ public class TaskOrganizerTests extends WindowTestsBase { assertEquals(ACTIVITY_TYPE_UNDEFINED, lastReportedTiles.get(0).topActivityType); } + @Test + public void testHierarchyTransaction() { + final ArrayMap<IBinder, RunningTaskInfo> lastReportedTiles = new ArrayMap<>(); + ITaskOrganizer listener = new ITaskOrganizer.Stub() { + @Override + public void taskAppeared(RunningTaskInfo taskInfo) { } + + @Override + public void taskVanished(IWindowContainer container) { } + + @Override + public void transactionReady(int id, SurfaceControl.Transaction t) { } + + @Override + public void onTaskInfoChanged(RunningTaskInfo info) { + lastReportedTiles.put(info.token.asBinder(), info); + } + }; + mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer( + listener, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( + mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + RunningTaskInfo info2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( + mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + + final ActivityStack stack = createTaskStackOnDisplay( + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent); + final ActivityStack stack2 = createTaskStackOnDisplay( + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mDisplayContent); + + lastReportedTiles.clear(); + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.reparent(stack.mRemoteToken, info1.token, true /* onTop */); + wct.reparent(stack2.mRemoteToken, info2.token, true /* onTop */); + mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(wct, + null /* organizer */); + assertFalse(lastReportedTiles.isEmpty()); + assertEquals(ACTIVITY_TYPE_STANDARD, + lastReportedTiles.get(info1.token.asBinder()).topActivityType); + assertEquals(ACTIVITY_TYPE_HOME, + lastReportedTiles.get(info2.token.asBinder()).topActivityType); + + lastReportedTiles.clear(); + wct = new WindowContainerTransaction(); + wct.reparent(stack2.mRemoteToken, info1.token, false /* onTop */); + mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(wct, + null /* organizer */); + assertFalse(lastReportedTiles.isEmpty()); + // Standard should still be on top of tile 1, so no change there + assertFalse(lastReportedTiles.containsKey(info1.token.asBinder())); + // But tile 2 has no children, so should become undefined + assertEquals(ACTIVITY_TYPE_UNDEFINED, + lastReportedTiles.get(info2.token.asBinder()).topActivityType); + + // Check the getChildren call + List<RunningTaskInfo> children = + mWm.mAtmService.mTaskOrganizerController.getChildTasks(info1.token); + assertEquals(2, children.size()); + children = mWm.mAtmService.mTaskOrganizerController.getChildTasks(info2.token); + assertEquals(0, children.size()); + + lastReportedTiles.clear(); + wct = new WindowContainerTransaction(); + wct.reorder(stack2.mRemoteToken, true /* onTop */); + mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(wct, + null /* organizer */); + // Home should now be on top. No change occurs in second tile, so not reported + assertEquals(1, lastReportedTiles.size()); + assertEquals(ACTIVITY_TYPE_HOME, + lastReportedTiles.get(info1.token.asBinder()).topActivityType); + } + private List<TaskTile> getTaskTiles(DisplayContent dc) { ArrayList<TaskTile> out = new ArrayList<>(); for (int i = dc.getStackCount() - 1; i >= 0; --i) { diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java index e16fffa69f8a..e1aec0a593b4 100644 --- a/telephony/java/android/telephony/euicc/EuiccCardManager.java +++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.Context; +import android.os.Binder; import android.os.RemoteException; import android.service.euicc.EuiccProfileInfo; import android.telephony.TelephonyFrameworkInitializer; @@ -168,7 +169,12 @@ public class EuiccCardManager { new IGetAllProfilesCallback.Stub() { @Override public void onComplete(int resultCode, EuiccProfileInfo[] profiles) { - executor.execute(() -> callback.onComplete(resultCode, profiles)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, profiles)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -192,7 +198,12 @@ public class EuiccCardManager { new IGetProfileCallback.Stub() { @Override public void onComplete(int resultCode, EuiccProfileInfo profile) { - executor.execute(() -> callback.onComplete(resultCode, profile)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, profile)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -217,7 +228,12 @@ public class EuiccCardManager { refresh, new IDisableProfileCallback.Stub() { @Override public void onComplete(int resultCode) { - executor.execute(() -> callback.onComplete(resultCode, null)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, null)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -243,7 +259,12 @@ public class EuiccCardManager { refresh, new ISwitchToProfileCallback.Stub() { @Override public void onComplete(int resultCode, EuiccProfileInfo profile) { - executor.execute(() -> callback.onComplete(resultCode, profile)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, profile)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -268,7 +289,12 @@ public class EuiccCardManager { nickname, new ISetNicknameCallback.Stub() { @Override public void onComplete(int resultCode) { - executor.execute(() -> callback.onComplete(resultCode, null)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, null)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -292,7 +318,12 @@ public class EuiccCardManager { new IDeleteProfileCallback.Stub() { @Override public void onComplete(int resultCode) { - executor.execute(() -> callback.onComplete(resultCode, null)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, null)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -317,7 +348,12 @@ public class EuiccCardManager { new IResetMemoryCallback.Stub() { @Override public void onComplete(int resultCode) { - executor.execute(() -> callback.onComplete(resultCode, null)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, null)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -340,7 +376,12 @@ public class EuiccCardManager { new IGetDefaultSmdpAddressCallback.Stub() { @Override public void onComplete(int resultCode, String address) { - executor.execute(() -> callback.onComplete(resultCode, address)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, address)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -363,7 +404,12 @@ public class EuiccCardManager { new IGetSmdsAddressCallback.Stub() { @Override public void onComplete(int resultCode, String address) { - executor.execute(() -> callback.onComplete(resultCode, address)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, address)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -388,7 +434,12 @@ public class EuiccCardManager { new ISetDefaultSmdpAddressCallback.Stub() { @Override public void onComplete(int resultCode) { - executor.execute(() -> callback.onComplete(resultCode, null)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, null)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -411,7 +462,12 @@ public class EuiccCardManager { new IGetRulesAuthTableCallback.Stub() { @Override public void onComplete(int resultCode, EuiccRulesAuthTable rat) { - executor.execute(() -> callback.onComplete(resultCode, rat)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, rat)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -434,7 +490,12 @@ public class EuiccCardManager { new IGetEuiccChallengeCallback.Stub() { @Override public void onComplete(int resultCode, byte[] challenge) { - executor.execute(() -> callback.onComplete(resultCode, challenge)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, challenge)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -457,7 +518,12 @@ public class EuiccCardManager { new IGetEuiccInfo1Callback.Stub() { @Override public void onComplete(int resultCode, byte[] info) { - executor.execute(() -> callback.onComplete(resultCode, info)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, info)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -480,7 +546,12 @@ public class EuiccCardManager { new IGetEuiccInfo2Callback.Stub() { @Override public void onComplete(int resultCode, byte[] info) { - executor.execute(() -> callback.onComplete(resultCode, info)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, info)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -522,7 +593,12 @@ public class EuiccCardManager { new IAuthenticateServerCallback.Stub() { @Override public void onComplete(int resultCode, byte[] response) { - executor.execute(() -> callback.onComplete(resultCode, response)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, response)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -561,7 +637,12 @@ public class EuiccCardManager { new IPrepareDownloadCallback.Stub() { @Override public void onComplete(int resultCode, byte[] response) { - executor.execute(() -> callback.onComplete(resultCode, response)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, response)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -589,7 +670,12 @@ public class EuiccCardManager { new ILoadBoundProfilePackageCallback.Stub() { @Override public void onComplete(int resultCode, byte[] response) { - executor.execute(() -> callback.onComplete(resultCode, response)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, response)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -619,7 +705,12 @@ public class EuiccCardManager { new ICancelSessionCallback.Stub() { @Override public void onComplete(int resultCode, byte[] response) { - executor.execute(() -> callback.onComplete(resultCode, response)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, response)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -643,7 +734,13 @@ public class EuiccCardManager { new IListNotificationsCallback.Stub() { @Override public void onComplete(int resultCode, EuiccNotification[] notifications) { - executor.execute(() -> callback.onComplete(resultCode, notifications)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete( + resultCode, notifications)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -667,7 +764,13 @@ public class EuiccCardManager { events, new IRetrieveNotificationListCallback.Stub() { @Override public void onComplete(int resultCode, EuiccNotification[] notifications) { - executor.execute(() -> callback.onComplete(resultCode, notifications)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete( + resultCode, notifications)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -691,7 +794,13 @@ public class EuiccCardManager { seqNumber, new IRetrieveNotificationCallback.Stub() { @Override public void onComplete(int resultCode, EuiccNotification notification) { - executor.execute(() -> callback.onComplete(resultCode, notification)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete( + resultCode, notification)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { @@ -718,7 +827,12 @@ public class EuiccCardManager { new IRemoveNotificationFromListCallback.Stub() { @Override public void onComplete(int resultCode) { - executor.execute(() -> callback.onComplete(resultCode, null)); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> callback.onComplete(resultCode, null)); + } finally { + Binder.restoreCallingIdentity(token); + } } }); } catch (RemoteException e) { diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp index 98e7b4e1b430..89005da27709 100644 --- a/tests/RollbackTest/Android.bp +++ b/tests/RollbackTest/Android.bp @@ -36,6 +36,15 @@ java_test_host { } java_test_host { + name: "NetworkStagedRollbackTest", + srcs: ["NetworkStagedRollbackTest/src/**/*.java"], + libs: ["tradefed"], + static_libs: ["testng"], + test_suites: ["general-tests"], + test_config: "NetworkStagedRollbackTest.xml", +} + +java_test_host { name: "MultiUserRollbackTest", srcs: ["MultiUserRollbackTest/src/**/*.java"], libs: ["tradefed"], diff --git a/tests/RollbackTest/NetworkStagedRollbackTest.xml b/tests/RollbackTest/NetworkStagedRollbackTest.xml new file mode 100644 index 000000000000..a465a4fe578b --- /dev/null +++ b/tests/RollbackTest/NetworkStagedRollbackTest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 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 the network staged rollback tests"> + <option name="test-suite-tag" value="NetworkStagedRollbackTest" /> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="RollbackTest.apk" /> + </target_preparer> + <test class="com.android.tradefed.testtype.HostTest" > + <option name="class" value="com.android.tests.rollback.host.NetworkStagedRollbackTest" /> + </test> +</configuration> diff --git a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java new file mode 100644 index 000000000000..2c2e8282ff51 --- /dev/null +++ b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 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.tests.rollback.host; + +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Runs the network rollback tests. + */ +@RunWith(DeviceJUnit4ClassRunner.class) +public class NetworkStagedRollbackTest extends BaseHostJUnit4Test { + /** + * Tests failed network health check triggers watchdog staged rollbacks. + */ + @Test + public void testNetworkFailedRollback() throws Exception { + } + + /** + * Tests passed network health check does not trigger watchdog staged rollbacks. + */ + @Test + public void testNetworkPassedDoesNotRollback() throws Exception { + } +} diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml index a14b01c57b1b..f2c0f86c3ce1 100644 --- a/tests/RollbackTest/RollbackTest.xml +++ b/tests/RollbackTest/RollbackTest.xml @@ -22,9 +22,9 @@ <option name="package" value="com.android.tests.rollback" /> <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> - <!-- Exclude the StagedRollbackTest and MultiUserRollbackTest tests, which need to be - specially driven from the StagedRollbackTest and MultiUserRollbackTest host test --> + <!-- Exclude the device tests which need to be specially driven from the host tests --> <option name="exclude-filter" value="com.android.tests.rollback.StagedRollbackTest" /> + <option name="exclude-filter" value="com.android.tests.rollback.NetworkStagedRollbackTest" /> <option name="exclude-filter" value="com.android.tests.rollback.MultiUserRollbackTest" /> </test> </configuration> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/AppName.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java index 1dbca0cd5527..04004d6abb5a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/AppName.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java @@ -14,17 +14,11 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification.row.dagger; +package com.android.tests.rollback; -import static java.lang.annotation.RetentionPolicy.RUNTIME; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; - -import javax.inject.Qualifier; - -@Qualifier -@Documented -@Retention(RUNTIME) -public @interface AppName { +@RunWith(JUnit4.class) +public class NetworkStagedRollbackTest { } diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java index c8fd2434e64f..0db3313ae137 100644 --- a/wifi/java/android/net/wifi/SoftApConfiguration.java +++ b/wifi/java/android/net/wifi/SoftApConfiguration.java @@ -519,6 +519,9 @@ public final class SoftApConfiguration implements Parcelable { case BAND_5GHZ: wifiConfig.apBand = WifiConfiguration.AP_BAND_5GHZ; break; + case BAND_2GHZ | BAND_5GHZ: + wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY; + break; case BAND_ANY: wifiConfig.apBand = WifiConfiguration.AP_BAND_ANY; break; diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 1682023c3312..5ccc3aa429c6 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -2982,7 +2982,7 @@ public class WifiManager { } /** - * Start Soft AP (hotspot) mode with the specified configuration. + * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration. * Note that starting Soft AP mode may disable station mode operation if the device does not * support concurrency. * @param wifiConfig SSID, security and channel details as part of WifiConfiguration, or null to @@ -3278,7 +3278,7 @@ public class WifiManager { } /** - * Gets the Wi-Fi enabled state. + * Gets the tethered Wi-Fi hotspot enabled state. * @return One of {@link #WIFI_AP_STATE_DISABLED}, * {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED}, * {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED} @@ -3297,8 +3297,8 @@ public class WifiManager { } /** - * Return whether Wi-Fi AP is enabled or disabled. - * @return {@code true} if Wi-Fi AP is enabled + * Return whether tethered Wi-Fi AP is enabled or disabled. + * @return {@code true} if tethered Wi-Fi AP is enabled * @see #getWifiApState() * * @hide @@ -3310,7 +3310,7 @@ public class WifiManager { } /** - * Gets the Wi-Fi AP Configuration. + * Gets the tethered Wi-Fi AP Configuration. * @return AP details in WifiConfiguration * * Note that AP detail may contain configuration which is cannot be represented @@ -3332,7 +3332,7 @@ public class WifiManager { } /** - * Gets the Wi-Fi AP Configuration. + * Gets the Wi-Fi tethered AP Configuration. * @return AP details in {@link SoftApConfiguration} * * @hide @@ -3349,7 +3349,7 @@ public class WifiManager { } /** - * Sets the Wi-Fi AP Configuration. + * Sets the tethered Wi-Fi AP Configuration. * @return {@code true} if the operation succeeded, {@code false} otherwise * * @deprecated This API is deprecated. Use {@link #setSoftApConfiguration(SoftApConfiguration)} @@ -3368,9 +3368,9 @@ public class WifiManager { } /** - * Sets the Wi-Fi AP Configuration. + * Sets the tethered Wi-Fi AP Configuration. * - * If the API is called while the soft AP is enabled, the configuration will apply to + * If the API is called while the tethered soft AP is enabled, the configuration will apply to * the current soft AP if the new configuration only includes * {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)} * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(int)} diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java index 2efdd97543a9..d9584885a045 100644 --- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java @@ -287,17 +287,43 @@ public class SoftApConfigurationTest { @Test public void testToWifiConfigurationWithSupportedParameter() { - SoftApConfiguration softApConfig = new SoftApConfiguration.Builder() + SoftApConfiguration softApConfig_2g = new SoftApConfiguration.Builder() + .setPassphrase("secretsecret", + SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) + .setChannel(11, SoftApConfiguration.BAND_2GHZ) + .setHiddenSsid(true) + .build(); + WifiConfiguration wifiConfig_2g = softApConfig_2g.toWifiConfiguration(); + assertThat(wifiConfig_2g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK); + assertThat(wifiConfig_2g.preSharedKey).isEqualTo("secretsecret"); + assertThat(wifiConfig_2g.apBand).isEqualTo(WifiConfiguration.AP_BAND_2GHZ); + assertThat(wifiConfig_2g.apChannel).isEqualTo(11); + assertThat(wifiConfig_2g.hiddenSSID).isEqualTo(true); + + SoftApConfiguration softApConfig_5g = new SoftApConfiguration.Builder() .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) .setChannel(149, SoftApConfiguration.BAND_5GHZ) .setHiddenSsid(true) .build(); - WifiConfiguration wifiConfig = softApConfig.toWifiConfiguration(); - assertThat(wifiConfig.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK); - assertThat(wifiConfig.preSharedKey).isEqualTo("secretsecret"); - assertThat(wifiConfig.apBand).isEqualTo(WifiConfiguration.AP_BAND_5GHZ); - assertThat(wifiConfig.apChannel).isEqualTo(149); - assertThat(wifiConfig.hiddenSSID).isEqualTo(true); + WifiConfiguration wifiConfig_5g = softApConfig_5g.toWifiConfiguration(); + assertThat(wifiConfig_5g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK); + assertThat(wifiConfig_5g.preSharedKey).isEqualTo("secretsecret"); + assertThat(wifiConfig_5g.apBand).isEqualTo(WifiConfiguration.AP_BAND_5GHZ); + assertThat(wifiConfig_5g.apChannel).isEqualTo(149); + assertThat(wifiConfig_5g.hiddenSSID).isEqualTo(true); + + SoftApConfiguration softApConfig_2g5g = new SoftApConfiguration.Builder() + .setPassphrase("secretsecret", + SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) + .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ) + .setHiddenSsid(true) + .build(); + WifiConfiguration wifiConfig_2g5g = softApConfig_2g5g.toWifiConfiguration(); + assertThat(wifiConfig_2g5g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK); + assertThat(wifiConfig_2g5g.preSharedKey).isEqualTo("secretsecret"); + assertThat(wifiConfig_2g5g.apBand).isEqualTo(WifiConfiguration.AP_BAND_ANY); + assertThat(wifiConfig_2g5g.apChannel).isEqualTo(0); + assertThat(wifiConfig_2g5g.hiddenSSID).isEqualTo(true); } } |