From 5e18c43fa7cd0084202a6f092f8a30e826ad9ae1 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 26 Aug 2019 12:48:49 -0700 Subject: Do not crash on invalid dataspace Prior logic caused device to crash when setting the dataspace for a layer to hdr on a non-hdr device. Update to log the failure and perform a no-op to match framework APIs. Bug: 140029823 Test: build, boot, CtsViewTestCases:android.view.cts.ASurfaceControlTest Change-Id: I9baf88a6d787e043b440ad4c2ebeb4c7a1fd90a2 --- native/android/surface_control.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'native/android') diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index 8fe4fecceeb5..53c01226ca1a 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -100,7 +100,11 @@ static bool isDataSpaceValid(const sp& surfaceControl, ADataSpac return getWideColorSupport(surfaceControl); // These data space need HDR support. case HAL_DATASPACE_BT2020_PQ: - return getHdrSupport(surfaceControl); + if (!getHdrSupport(surfaceControl)) { + ALOGE("Invalid dataspace - device does not support hdr"); + return false; + } + return true; default: return false; } @@ -458,10 +462,11 @@ void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* aSurfaceTransac CHECK_NOT_NULL(aSurfaceControl); sp surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); - LOG_ALWAYS_FATAL_IF(!isDataSpaceValid(surfaceControl, aDataSpace), "invalid dataspace"); - + if (!isDataSpaceValid(surfaceControl, aDataSpace)) { + ALOGE("Failed to set buffer dataspace - invalid dataspace"); + return; + } Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); - transaction->setDataspace(surfaceControl, static_cast(aDataSpace)); } @@ -527,7 +532,10 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction, CHECK_NOT_NULL(aSurfaceControl); sp surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); - LOG_ALWAYS_FATAL_IF(!isDataSpaceValid(surfaceControl, dataspace), "invalid dataspace"); + if (!isDataSpaceValid(surfaceControl, dataspace)) { + ALOGE("Failed to set buffer dataspace - invalid dataspace"); + return; + } Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); half3 color; -- cgit v1.2.3-59-g8ed1b From 874883536af0b421cc43d1e5f77dc3cf8e7f1756 Mon Sep 17 00:00:00 2001 From: atrost Date: Thu, 10 Oct 2019 19:27:31 +0100 Subject: Add a native aidl API. Introduce a platform_compat_native service that just calls the platform_compat service. The new service is needed as it needs a slightly different (more limited, no ApplicationInfo in cpp) aidl API, and a class can only extend one stub. Test: Call the service from dumpsys.cpp (http://aosp/1142055) Bug: 138275545 Change-Id: Ic46cc34b4c1dd4ebc6bcc996fb3f8503607214ac --- Android.bp | 3 + core/java/android/content/Context.java | 10 +++ native/android/Android.bp | 33 ++++++++ .../internal/compat/IPlatformCompatNative.aidl | 91 ++++++++++++++++++++++ .../server/compat/PlatformCompatNative.java | 50 ++++++++++++ services/java/com/android/server/SystemServer.java | 7 +- 6 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl create mode 100644 services/core/java/com/android/server/compat/PlatformCompatNative.java (limited to 'native/android') diff --git a/Android.bp b/Android.bp index 05474815f62c..43c6469ce600 100644 --- a/Android.bp +++ b/Android.bp @@ -213,6 +213,9 @@ filegroup { ":PacProcessor-aidl-sources", ":ProxyHandler-aidl-sources", + // AIDL from frameworks/base/native/ + ":platform-compat-native-aidl", + // AIDL sources from external directories ":dumpstate_aidl", ":framework_native_aidl", diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index e7e278f431ba..bb10e1c2ee74 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -74,6 +74,7 @@ import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient; import android.view.textclassifier.TextClassificationManager; import com.android.internal.compat.IPlatformCompat; +import com.android.internal.compat.IPlatformCompatNative; import java.io.File; import java.io.FileInputStream; @@ -3243,6 +3244,7 @@ public abstract class Context { //@hide ROLE_CONTROLLER_SERVICE, CAMERA_SERVICE, //@hide: PLATFORM_COMPAT_SERVICE, + //@hide: PLATFORM_COMPAT_NATIVE_SERVICE, PRINT_SERVICE, CONSUMER_IR_SERVICE, //@hide: TRUST_SERVICE, @@ -4619,6 +4621,14 @@ public abstract class Context { */ public static final String PLATFORM_COMPAT_SERVICE = "platform_compat"; + /** + * Use with {@link android.os.ServiceManager.getService()} to retrieve a + * {@link IPlatformCompatNative} IBinder for native code communicating with the platform compat + * service. + * @hide + */ + public static final String PLATFORM_COMPAT_NATIVE_SERVICE = "platform_compat_native"; + /** * Service to capture a bugreport. * @see #getSystemService(String) diff --git a/native/android/Android.bp b/native/android/Android.bp index 7c1af4a81f9d..91297b0de02e 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -110,3 +110,36 @@ llndk_library { symbol_file: "libandroid_net.map.txt", unversioned: true, } + + +// Aidl library for platform compat. +cc_library_shared { + name: "lib-platform-compat-native-api", + cflags: [ + "-Wall", + "-Werror", + "-Wno-missing-field-initializers", + "-Wno-unused-variable", + "-Wunused-parameter", + ], + shared_libs: [ + "libbinder", + "libutils", + ], + aidl: { + local_include_dirs: ["aidl"], + export_aidl_headers: true, + }, + srcs: [ + ":platform-compat-native-aidl", + ], + export_include_dirs: ["aidl"], +} + +filegroup { + name: "platform-compat-native-aidl", + srcs: [ + "aidl/com/android/internal/compat/IPlatformCompatNative.aidl", + ], + path: "aidl", +} \ No newline at end of file diff --git a/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl b/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl new file mode 100644 index 000000000000..c022388e0aa8 --- /dev/null +++ b/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package com.android.internal.compat; + +/** + * Platform native private API for talking with the PlatformCompat service. + * + *

Should be used for gating and logging from non-app processes running cpp code. + * For app processes please use android.compat.Compatibility API. + * + * {@hide} + */ +interface IPlatformCompatNative +{ + /** + * Reports that a compatibility change is affecting an app process now. + * + *

Note: for changes that are gated using {@link #isChangeEnabled(long, String)}, + * you do not need to call this API directly. The change will be reported for you. + * + * @param changeId The ID of the compatibility change taking effect. + * @param packageName The package name of the app in question. + */ + void reportChangeByPackageName(long changeId, @utf8InCpp String packageName); + + /** + * Reports that a compatibility change is affecting an app process now. + * + *

Note: for changes that are gated using {@link #isChangeEnabled(long, int)}, + * you do not need to call this API directly. The change will be reported for you. + * + * @param changeId The ID of the compatibility change taking effect. + * @param uid The UID of the app in question. + */ + void reportChangeByUid(long changeId, int uid); + + /** + * Query if a given compatibility change is enabled for an app process. This method should + * be called when implementing functionality on behalf of the affected app. + * + *

Returns {@code true} if there is no installed package by the provided package name. + * + *

If this method returns {@code true}, the calling code should implement the compatibility + * change, resulting in differing behaviour compared to earlier releases. If this method + * returns + * {@code false}, the calling code should behave as it did in earlier releases. + * + *

It will also report the change as {@link #reportChange(long, String)} would, so there is + * no need to call that method directly. + * + * @param changeId The ID of the compatibility change in question. + * @param packageName The package name of the app in question. + * @return {@code true} if the change is enabled for the current app. + */ + boolean isChangeEnabledByPackageName(long changeId, @utf8InCpp String packageName); + + /** + * Query if a given compatibility change is enabled for an app process. This method should + * be called when implementing functionality on behalf of the affected app. + * + *

Returns {@code true} if there are no installed packages for the required UID, or if the + * change is enabled for ALL of the installed packages associated with the provided UID. Please + * use a more specific API if you want a different behaviour for multi-package UIDs. + * + *

If this method returns {@code true}, the calling code should implement the compatibility + * change, resulting in differing behaviour compared to earlier releases. If this method + * returns {@code false}, the calling code should behave as it did in earlier releases. + * + *

It will also report the change as {@link #reportChange(long, int)} would, so there is + * no need to call that method directly. + * + * @param changeId The ID of the compatibility change in question. + * @param uid The UID of the app in question. + * @return {@code true} if the change is enabled for the current app. + */ + boolean isChangeEnabledByUid(long changeId, int uid); +} \ No newline at end of file diff --git a/services/core/java/com/android/server/compat/PlatformCompatNative.java b/services/core/java/com/android/server/compat/PlatformCompatNative.java new file mode 100644 index 000000000000..839967139baa --- /dev/null +++ b/services/core/java/com/android/server/compat/PlatformCompatNative.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package com.android.server.compat; + +import com.android.internal.compat.IPlatformCompatNative; + +/** + * @hide + */ +public class PlatformCompatNative extends IPlatformCompatNative.Stub { + private final PlatformCompat mPlatformCompat; + + public PlatformCompatNative(PlatformCompat platformCompat) { + mPlatformCompat = platformCompat; + } + + @Override + public void reportChangeByPackageName(long changeId, String packageName) { + mPlatformCompat.reportChangeByPackageName(changeId, packageName); + } + + @Override + public void reportChangeByUid(long changeId, int uid) { + mPlatformCompat.reportChangeByUid(changeId, uid); + } + + @Override + public boolean isChangeEnabledByPackageName(long changeId, String packageName) { + return mPlatformCompat.isChangeEnabledByPackageName(changeId, packageName); + } + + @Override + public boolean isChangeEnabledByUid(long changeId, int uid) { + return mPlatformCompat.isChangeEnabledByUid(changeId, uid); + } +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 88859a71d135..58830487a0fe 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -90,6 +90,7 @@ import com.android.server.broadcastradio.BroadcastRadioService; import com.android.server.camera.CameraServiceProxy; import com.android.server.clipboard.ClipboardService; import com.android.server.compat.PlatformCompat; +import com.android.server.compat.PlatformCompatNative; import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.coverage.CoverageService; @@ -641,8 +642,10 @@ public final class SystemServer { // Platform compat service is used by ActivityManagerService, PackageManagerService, and // possibly others in the future. b/135010838. t.traceBegin("PlatformCompat"); - ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, - new PlatformCompat(mSystemContext)); + PlatformCompat platformCompat = new PlatformCompat(mSystemContext); + ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat); + ServiceManager.addService(Context.PLATFORM_COMPAT_NATIVE_SERVICE, + new PlatformCompatNative(platformCompat)); t.traceEnd(); // Wait for installd to finish starting up so that it has a chance to -- cgit v1.2.3-59-g8ed1b From ec453e14237462b6f6e79077a698fe636fd86acb Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 21 Oct 2019 14:43:28 -0700 Subject: Adding transformHint to callbacks Bug: 141939598, 133512804 Test: build, boot, manual Change-Id: I58411368e5187b3a23eb9e8ac9abbf1cb1a5d97e --- native/android/surface_control.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'native/android') diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index 53c01226ca1a..b34b31ac8439 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -294,7 +294,7 @@ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* aSurfaceTransaction, auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats; - for (const auto& [surfaceControl, acquireTime, previousReleaseFence] : surfaceControlStats) { + for (const auto& [surfaceControl, acquireTime, previousReleaseFence, transformHint] : surfaceControlStats) { ASurfaceControl* aSurfaceControl = reinterpret_cast(surfaceControl.get()); aSurfaceControlStats[aSurfaceControl].acquireTime = acquireTime; aSurfaceControlStats[aSurfaceControl].previousReleaseFence = previousReleaseFence; -- cgit v1.2.3-59-g8ed1b From 53bca9377da58f31e0eb21bbcef16cffc5b1f687 Mon Sep 17 00:00:00 2001 From: atrost Date: Tue, 22 Oct 2019 15:26:16 +0100 Subject: Add userId to the package name API. The service would query package manager with the provided userId, and will return true if the package is not visible. Bug: 142942524 Bug: 143129258 Test: m, treehugger Change-Id: I92ea650b49743c388bff9943a7ec620e3d61a5d6 --- .../com/android/internal/compat/IPlatformCompat.aidl | 8 +++++--- .../android/internal/compat/IPlatformCompatNative.aidl | 6 ++++-- .../java/com/android/server/compat/PlatformCompat.java | 18 +++++++++--------- .../android/server/compat/PlatformCompatNative.java | 8 ++++---- .../devicepolicy/DevicePolicyManagerService.java | 2 +- 5 files changed, 23 insertions(+), 19 deletions(-) (limited to 'native/android') diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index 4099cfa51b33..8391ad2f12c2 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -49,9 +49,10 @@ interface IPlatformCompat * you do not need to call this API directly. The change will be reported for you. * * @param changeId The ID of the compatibility change taking effect. + * @param userId The ID of the user that the operation is done for. * @param packageName The package name of the app in question. */ - void reportChangeByPackageName(long changeId, in String packageName); + void reportChangeByPackageName(long changeId, in String packageName, int userId); /** * Reports that a compatibility change is affecting an app process now. @@ -86,7 +87,7 @@ interface IPlatformCompat * be called when implementing functionality on behalf of the affected app. * *

Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a package name - * instead of an {@link ApplicationInfo} + * and userId instead of an {@link ApplicationInfo} * object, and finds an app info object based on the package name. Returns {@code true} if * there is no installed package by that name. * @@ -100,9 +101,10 @@ interface IPlatformCompat * * @param changeId The ID of the compatibility change in question. * @param packageName The package name of the app in question. + * @param userId The ID of the user that the operation is done for. * @return {@code true} if the change is enabled for the current app. */ - boolean isChangeEnabledByPackageName(long changeId, in String packageName); + boolean isChangeEnabledByPackageName(long changeId, in String packageName, int userId); /** * Query if a given compatibility change is enabled for an app process. This method should diff --git a/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl b/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl index c022388e0aa8..347e4e8ebe4b 100644 --- a/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl +++ b/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl @@ -33,9 +33,10 @@ interface IPlatformCompatNative * you do not need to call this API directly. The change will be reported for you. * * @param changeId The ID of the compatibility change taking effect. + * @param userId The ID of the user that the operation is done for. * @param packageName The package name of the app in question. */ - void reportChangeByPackageName(long changeId, @utf8InCpp String packageName); + void reportChangeByPackageName(long changeId, @utf8InCpp String packageName, int userId); /** * Reports that a compatibility change is affecting an app process now. @@ -64,9 +65,10 @@ interface IPlatformCompatNative * * @param changeId The ID of the compatibility change in question. * @param packageName The package name of the app in question. + * @param userId The ID of the user that the operation is done for. * @return {@code true} if the change is enabled for the current app. */ - boolean isChangeEnabledByPackageName(long changeId, @utf8InCpp String packageName); + boolean isChangeEnabledByPackageName(long changeId, @utf8InCpp String packageName, int userId); /** * Query if a given compatibility change is enabled for an app process. This method should diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 854f16aeb54e..9ac9955493cc 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -19,7 +19,7 @@ package com.android.server.compat; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.os.Process; +import android.os.UserHandle; import android.util.Slog; import android.util.StatsLog; @@ -54,8 +54,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { } @Override - public void reportChangeByPackageName(long changeId, String packageName) { - ApplicationInfo appInfo = getApplicationInfo(packageName); + public void reportChangeByPackageName(long changeId, String packageName, int userId) { + ApplicationInfo appInfo = getApplicationInfo(packageName, userId); if (appInfo == null) { return; } @@ -80,8 +80,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { } @Override - public boolean isChangeEnabledByPackageName(long changeId, String packageName) { - ApplicationInfo appInfo = getApplicationInfo(packageName); + public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) { + ApplicationInfo appInfo = getApplicationInfo(packageName, userId); if (appInfo == null) { return true; } @@ -96,7 +96,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { } boolean enabled = true; for (String packageName : packages) { - enabled = enabled && isChangeEnabledByPackageName(changeId, packageName); + enabled = enabled && isChangeEnabledByPackageName(changeId, packageName, + UserHandle.getUserId(uid)); } return enabled; } @@ -127,10 +128,9 @@ public class PlatformCompat extends IPlatformCompat.Stub { mChangeReporter.resetReportedChanges(appInfo.uid); } - private ApplicationInfo getApplicationInfo(String packageName) { + private ApplicationInfo getApplicationInfo(String packageName, int userId) { try { - return mContext.getPackageManager().getApplicationInfoAsUser(packageName, 0, - Process.myUid()); + return mContext.getPackageManager().getApplicationInfoAsUser(packageName, 0, userId); } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "No installed package " + packageName); } diff --git a/services/core/java/com/android/server/compat/PlatformCompatNative.java b/services/core/java/com/android/server/compat/PlatformCompatNative.java index 839967139baa..85dfbf411667 100644 --- a/services/core/java/com/android/server/compat/PlatformCompatNative.java +++ b/services/core/java/com/android/server/compat/PlatformCompatNative.java @@ -29,8 +29,8 @@ public class PlatformCompatNative extends IPlatformCompatNative.Stub { } @Override - public void reportChangeByPackageName(long changeId, String packageName) { - mPlatformCompat.reportChangeByPackageName(changeId, packageName); + public void reportChangeByPackageName(long changeId, String packageName, int userId) { + mPlatformCompat.reportChangeByPackageName(changeId, packageName, userId); } @Override @@ -39,8 +39,8 @@ public class PlatformCompatNative extends IPlatformCompatNative.Stub { } @Override - public boolean isChangeEnabledByPackageName(long changeId, String packageName) { - return mPlatformCompat.isChangeEnabledByPackageName(changeId, packageName); + public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) { + return mPlatformCompat.isChangeEnabledByPackageName(changeId, packageName, userId); } @Override diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index c4adc035d613..21bcaa87431f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -4178,7 +4178,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private boolean passwordQualityInvocationOrderCheckEnabled(String packageName, int userId) { try { return mIPlatformCompat.isChangeEnabledByPackageName(ADMIN_APP_PASSWORD_COMPLEXITY, - packageName); + packageName, userId); } catch (RemoteException e) { Log.e(LOG_TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e); } -- cgit v1.2.3-59-g8ed1b From 01709c7469b59e451f064c266bbe442e9bef0ab4 Mon Sep 17 00:00:00 2001 From: Seigo Nonaka Date: Thu, 24 Oct 2019 18:50:51 -0700 Subject: Make AFont_getLocale work There are multiple problems here: - Java Font.equals and hashCode doesn't look at locale list. Due to this issue, the CTS tests have been passing unexpectedly. - The null pointer check in the AFont_getLoacle was inversed. Should return only when it is non-null. - Looks like we cannot get the parent's attribute which always returns null. Instead, read the "lang" attribute when we read the family tag. Bug: 139201432 Test: atest NativeSystemFontTest Test: atest TypefaceEqualsTest Change-Id: I0514847bbf46a73358afab374ccfce2db09b2ec0 --- .../src/android/graphics/TypefaceEqualsTest.java | 56 ++++++++++++++++++++ graphics/java/android/graphics/fonts/Font.java | 5 +- native/android/system_fonts.cpp | 61 +++++++++++++--------- 3 files changed, 94 insertions(+), 28 deletions(-) create mode 100644 core/tests/coretests/src/android/graphics/TypefaceEqualsTest.java (limited to 'native/android') diff --git a/core/tests/coretests/src/android/graphics/TypefaceEqualsTest.java b/core/tests/coretests/src/android/graphics/TypefaceEqualsTest.java new file mode 100644 index 000000000000..6ae7eb72fab2 --- /dev/null +++ b/core/tests/coretests/src/android/graphics/TypefaceEqualsTest.java @@ -0,0 +1,56 @@ +/* + * 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.graphics; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.content.res.AssetManager; +import android.graphics.fonts.Font; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.IOException; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class TypefaceEqualsTest { + @Test + public void testFontEqualWithLocale() throws IOException { + final AssetManager am = + InstrumentationRegistry.getInstrumentation().getContext().getAssets(); + + Font masterFont = new Font.Builder(am, "fonts/a3em.ttf").build(); + + Font jaFont = new Font.Builder(masterFont.getBuffer(), new File("fonts/a3em.ttf"), "ja") + .build(); + Font jaFont2 = new Font.Builder(masterFont.getBuffer(), new File("fonts/a3em.ttf"), "ja") + .build(); + Font koFont = new Font.Builder(masterFont.getBuffer(), new File("fonts/a3em.ttf"), "ko") + .build(); + + assertEquals(jaFont, jaFont2); + assertNotEquals(jaFont, koFont); + assertNotEquals(jaFont, masterFont); + } +} diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index 552088f7c478..ba96a06cc852 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -519,12 +519,13 @@ public final class Font { } Font f = (Font) o; return mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex - && Arrays.equals(f.mAxes, mAxes) && f.mBuffer.equals(mBuffer); + && Arrays.equals(f.mAxes, mAxes) && f.mBuffer.equals(mBuffer) + && Objects.equals(f.mLocaleList, mLocaleList); } @Override public int hashCode() { - return Objects.hash(mFontStyle, mTtcIndex, Arrays.hashCode(mAxes), mBuffer); + return Objects.hash(mFontStyle, mTtcIndex, Arrays.hashCode(mAxes), mBuffer, mLocaleList); } @Override diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp index 9791da63359b..45f42f1b5dc6 100644 --- a/native/android/system_fonts.cpp +++ b/native/android/system_fonts.cpp @@ -16,6 +16,8 @@ #include +#define LOG_TAG "SystemFont" + #include #include #include @@ -47,9 +49,14 @@ struct XmlDocDeleter { using XmlCharUniquePtr = std::unique_ptr; using XmlDocUniquePtr = std::unique_ptr; +struct ParserState { + xmlNode* mFontNode = nullptr; + XmlCharUniquePtr mLocale; +}; + struct ASystemFontIterator { XmlDocUniquePtr mXmlDoc; - xmlNode* mFontNode; + ParserState state; // The OEM customization XML. XmlDocUniquePtr mCustomizationXmlDoc; @@ -97,6 +104,7 @@ std::string xmlTrim(const std::string& in) { const xmlChar* FAMILY_TAG = BAD_CAST("family"); const xmlChar* FONT_TAG = BAD_CAST("font"); +const xmlChar* LOCALE_ATTR_NAME = BAD_CAST("lang"); xmlNode* firstElement(xmlNode* node, const xmlChar* tag) { for (xmlNode* child = node->children; child; child = child->next) { @@ -116,9 +124,9 @@ xmlNode* nextSibling(xmlNode* node, const xmlChar* tag) { return nullptr; } -void copyFont(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode, AFont* out, +void copyFont(const XmlDocUniquePtr& xmlDoc, const ParserState& state, AFont* out, const std::string& pathPrefix) { - const xmlChar* LOCALE_ATTR_NAME = BAD_CAST("lang"); + xmlNode* fontNode = state.mFontNode; XmlCharUniquePtr filePathStr( xmlNodeListGetString(xmlDoc.get(), fontNode->xmlChildrenNode, 1)); out->mFilePath = pathPrefix + xmlTrim( @@ -139,9 +147,10 @@ void copyFont(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode, AFont* out, out->mCollectionIndex = indexStr ? strtol(reinterpret_cast(indexStr.get()), nullptr, 10) : 0; - XmlCharUniquePtr localeStr(xmlGetProp(xmlDoc->parent, LOCALE_ATTR_NAME)); out->mLocale.reset( - localeStr ? new std::string(reinterpret_cast(localeStr.get())) : nullptr); + state.mLocale ? + new std::string(reinterpret_cast(state.mLocale.get())) + : nullptr); const xmlChar* TAG_ATTR_NAME = BAD_CAST("tag"); const xmlChar* STYLEVALUE_ATTR_NAME = BAD_CAST("stylevalue"); @@ -178,25 +187,27 @@ bool isFontFileAvailable(const std::string& filePath) { return S_ISREG(st.st_mode); } -xmlNode* findFirstFontNode(const XmlDocUniquePtr& doc) { +bool findFirstFontNode(const XmlDocUniquePtr& doc, ParserState* state) { xmlNode* familySet = xmlDocGetRootElement(doc.get()); if (familySet == nullptr) { - return nullptr; + return false; } xmlNode* family = firstElement(familySet, FAMILY_TAG); if (family == nullptr) { - return nullptr; + return false; } + state->mLocale.reset(xmlGetProp(family, LOCALE_ATTR_NAME)); xmlNode* font = firstElement(family, FONT_TAG); while (font == nullptr) { family = nextSibling(family, FAMILY_TAG); if (family == nullptr) { - return nullptr; + return false; } font = firstElement(family, FONT_TAG); } - return font; + state->mFontNode = font; + return font != nullptr; } } // namespace @@ -272,38 +283,38 @@ AFont* _Nonnull AFontMatcher_match( return result.release(); } -xmlNode* findNextFontNode(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode) { - if (fontNode == nullptr) { +bool findNextFontNode(const XmlDocUniquePtr& xmlDoc, ParserState* state) { + if (state->mFontNode == nullptr) { if (!xmlDoc) { - return nullptr; // Already at the end. + return false; // Already at the end. } else { // First time to query font. - return findFirstFontNode(xmlDoc); + return findFirstFontNode(xmlDoc, state); } } else { - xmlNode* nextNode = nextSibling(fontNode, FONT_TAG); + xmlNode* nextNode = nextSibling(state->mFontNode, FONT_TAG); while (nextNode == nullptr) { - xmlNode* family = nextSibling(fontNode->parent, FAMILY_TAG); + xmlNode* family = nextSibling(state->mFontNode->parent, FAMILY_TAG); if (family == nullptr) { break; } + state->mLocale.reset(xmlGetProp(family, LOCALE_ATTR_NAME)); nextNode = firstElement(family, FONT_TAG); } - return nextNode; + state->mFontNode = nextNode; + return nextNode != nullptr; } } AFont* ASystemFontIterator_next(ASystemFontIterator* ite) { LOG_ALWAYS_FATAL_IF(ite == nullptr, "nullptr has passed as iterator argument"); if (ite->mXmlDoc) { - ite->mFontNode = findNextFontNode(ite->mXmlDoc, ite->mFontNode); - if (ite->mFontNode == nullptr) { + if (!findNextFontNode(ite->mXmlDoc, &ite->state)) { // Reached end of the XML file. Continue OEM customization. ite->mXmlDoc.reset(); - ite->mFontNode = nullptr; } else { std::unique_ptr font = std::make_unique(); - copyFont(ite->mXmlDoc, ite->mFontNode, font.get(), "/system/fonts/"); + copyFont(ite->mXmlDoc, ite->state, font.get(), "/system/fonts/"); if (!isFontFileAvailable(font->mFilePath)) { return ASystemFontIterator_next(ite); } @@ -312,15 +323,13 @@ AFont* ASystemFontIterator_next(ASystemFontIterator* ite) { } if (ite->mCustomizationXmlDoc) { // TODO: Filter only customizationType="new-named-family" - ite->mFontNode = findNextFontNode(ite->mCustomizationXmlDoc, ite->mFontNode); - if (ite->mFontNode == nullptr) { + if (!findNextFontNode(ite->mCustomizationXmlDoc, &ite->state)) { // Reached end of the XML file. Finishing ite->mCustomizationXmlDoc.reset(); - ite->mFontNode = nullptr; return nullptr; } else { std::unique_ptr font = std::make_unique(); - copyFont(ite->mCustomizationXmlDoc, ite->mFontNode, font.get(), "/product/fonts/"); + copyFont(ite->mCustomizationXmlDoc, ite->state, font.get(), "/product/fonts/"); if (!isFontFileAvailable(font->mFilePath)) { return ASystemFontIterator_next(ite); } @@ -351,7 +360,7 @@ bool AFont_isItalic(const AFont* font) { const char* AFont_getLocale(const AFont* font) { LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument"); - return font->mLocale ? nullptr : font->mLocale->c_str(); + return font->mLocale ? font->mLocale->c_str() : nullptr; } size_t AFont_getCollectionIndex(const AFont* font) { -- cgit v1.2.3-59-g8ed1b From a9258ab2e16669da63ad6a423bb65a11f3ad9a6c Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Wed, 6 Nov 2019 12:44:58 +0900 Subject: Rename # vndk tag to # llndk The APIs that are tagged with # vndk are actually for LLNDK libraries. Although LLNDK is part of VNDK, calling those APIs 'vndk' has given users a wrong perception that the APIs don't need to be kept stable because that's the norm for most of the VNDK libraries that are not LLNDK. In order to eliminate the misunderstanding, rename the tag to 'llndk' so that people introducing new such API will realize what they are signing themselves up for. Bug: 143765505 Test: m Change-Id: I7ae77e232ec25cbe7afd98d1b68fc7a7fcf9bdfd --- native/android/libandroid_net.map.txt | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'native/android') diff --git a/native/android/libandroid_net.map.txt b/native/android/libandroid_net.map.txt index be3531da462d..8d4e9009cc56 100644 --- a/native/android/libandroid_net.map.txt +++ b/native/android/libandroid_net.map.txt @@ -1,15 +1,19 @@ -# They are also all available to vendor code. +# The following symbols marked with # llndk are available to vendor code. +# Unlike other VNDK libraries where keeping backwards compatibility is required +# only within a platform release, these symbols need much longer suppport +# because the same LLNDK library serves for both system and vendor partition +# which might be a few years old. LIBANDROID_NET { global: # These functions have been part of the NDK since API 24. - android_getaddrinfofornetwork; # vndk - android_setsocknetwork; # vndk - android_setprocnetwork; # vndk + android_getaddrinfofornetwork; # llndk + android_setsocknetwork; # llndk + android_setprocnetwork; # llndk # These functions have been part of the NDK since API 29. - android_res_cancel; # vndk - android_res_nquery; # vndk - android_res_nresult; # vndk - android_res_nsend; # vndk + android_res_cancel; # llndk + android_res_nquery; # llndk + android_res_nresult; # llndk + android_res_nsend; # llndk local: *; }; -- cgit v1.2.3-59-g8ed1b From aaa9e834d443a56671eccbe97c755c253fa94afe Mon Sep 17 00:00:00 2001 From: Stan Iliev Date: Tue, 17 Sep 2019 14:07:23 -0400 Subject: Decouple SurfaceTexture from HWUI Remove all Skia and HWUI types from SurfaceTexture implementation. Move SurfaceTexture to libgui (ag/9578265). Define private C++ API for SurfaceTexture, which is consumed by DeferredLayerUpdater. Move AutoBackendTextureRelease/Skia code from SurfaceTexture to HWUI. Test: pass CtsUiRenderingTestCases and CtsViewTestCases Bug: 136263580 Change-Id: I3f971bb490f64a3ac0b2a66a89ba935bf7f08213 --- core/jni/Android.bp | 2 +- core/jni/android/graphics/SurfaceTexture.cpp | 6 +- ..._hardware_camera2_legacy_LegacyCameraDevice.cpp | 2 +- core/jni/android_view_TextureLayer.cpp | 9 +- .../android_graphics_SurfaceTexture.h | 2 + libs/hwui/Android.bp | 4 +- libs/hwui/AutoBackendTextureRelease.cpp | 91 +++ libs/hwui/AutoBackendTextureRelease.h | 67 ++ libs/hwui/DeferredLayerUpdater.cpp | 133 +++- libs/hwui/DeferredLayerUpdater.h | 50 +- libs/hwui/renderthread/EglManager.cpp | 44 +- libs/hwui/renderthread/EglManager.h | 6 +- libs/hwui/renderthread/RenderThread.h | 23 +- libs/hwui/renderthread/VulkanManager.cpp | 46 +- libs/hwui/renderthread/VulkanManager.h | 9 +- libs/hwui/surfacetexture/EGLConsumer.cpp | 675 --------------------- libs/hwui/surfacetexture/EGLConsumer.h | 311 ---------- libs/hwui/surfacetexture/ImageConsumer.cpp | 299 --------- libs/hwui/surfacetexture/ImageConsumer.h | 115 ---- libs/hwui/surfacetexture/SurfaceTexture.cpp | 499 --------------- libs/hwui/surfacetexture/SurfaceTexture.h | 452 -------------- libs/hwui/tests/common/TestUtils.h | 1 + native/android/surface_texture.cpp | 16 +- 23 files changed, 401 insertions(+), 2461 deletions(-) create mode 100644 libs/hwui/AutoBackendTextureRelease.cpp create mode 100644 libs/hwui/AutoBackendTextureRelease.h delete mode 100644 libs/hwui/surfacetexture/EGLConsumer.cpp delete mode 100644 libs/hwui/surfacetexture/EGLConsumer.h delete mode 100644 libs/hwui/surfacetexture/ImageConsumer.cpp delete mode 100644 libs/hwui/surfacetexture/ImageConsumer.h delete mode 100644 libs/hwui/surfacetexture/SurfaceTexture.cpp delete mode 100644 libs/hwui/surfacetexture/SurfaceTexture.h (limited to 'native/android') diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 30edc3721efb..ea1094913a26 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -179,6 +179,7 @@ cc_library_shared { "android_hardware_UsbRequest.cpp", "android_hardware_location_ActivityRecognitionHardware.cpp", "android_util_FileObserver.cpp", + "android/graphics/SurfaceTexture.cpp", "android/opengl/poly_clip.cpp", // TODO: .arm "android/opengl/util.cpp", "android_server_NetworkManagementSocketTagger.cpp", @@ -431,7 +432,6 @@ cc_library_static { "android/graphics/GIFMovie.cpp", "android/graphics/Movie.cpp", "android/graphics/MovieImpl.cpp", - "android/graphics/SurfaceTexture.cpp", "android/graphics/pdf/PdfDocument.cpp", "android/graphics/pdf/PdfEditor.cpp", "android/graphics/pdf/PdfRenderer.cpp", diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp index c74c2644c645..1a9e8d077e21 100644 --- a/core/jni/android/graphics/SurfaceTexture.cpp +++ b/core/jni/android/graphics/SurfaceTexture.cpp @@ -24,7 +24,9 @@ #include #include +#include #include +#include #include "core_jni_helpers.h" @@ -35,7 +37,6 @@ #include "jni.h" #include #include -#include "surfacetexture/SurfaceTexture.h" // ---------------------------------------------------------------------------- @@ -402,3 +403,6 @@ int register_android_graphics_SurfaceTexture(JNIEnv* env) } } // namespace android + +//TODO: Move this file to frameworks/base/core/jni/android_graphics_SurfaceTexture.cpp. See +//TODO: android_view_Surface.cpp for example. diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp index 87adbe8102c6..cb7f0ddee1ff 100644 --- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp +++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp @@ -26,9 +26,9 @@ #include "core_jni_helpers.h" #include "android_runtime/android_view_Surface.h" #include "android_runtime/android_graphics_SurfaceTexture.h" -#include "surfacetexture/SurfaceTexture.h" #include +#include #include #include #include diff --git a/core/jni/android_view_TextureLayer.cpp b/core/jni/android_view_TextureLayer.cpp index 8a3f54039d05..64751517d162 100644 --- a/core/jni/android_view_TextureLayer.cpp +++ b/core/jni/android_view_TextureLayer.cpp @@ -23,7 +23,9 @@ #include "core_jni_helpers.h" #include -#include +#include +#include +#include #include #include @@ -64,7 +66,10 @@ static void TextureLayer_setTransform(JNIEnv* env, jobject clazz, static void TextureLayer_setSurfaceTexture(JNIEnv* env, jobject clazz, jlong layerUpdaterPtr, jobject surface) { DeferredLayerUpdater* layer = reinterpret_cast(layerUpdaterPtr); - layer->setSurfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface)); + auto consumer = SurfaceTexture_getSurfaceTexture(env, surface); + auto producer = SurfaceTexture_getProducer(env, surface); + layer->setSurfaceTexture(AutoTextureRelease( + ASurfaceTexture_create(consumer, producer))); } static void TextureLayer_updateSurfaceTexture(JNIEnv* env, jobject clazz, diff --git a/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h b/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h index d3ff959e3ba7..e2d78915fd00 100644 --- a/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h +++ b/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h @@ -17,6 +17,8 @@ #ifndef _ANDROID_GRAPHICS_SURFACETEXTURE_H #define _ANDROID_GRAPHICS_SURFACETEXTURE_H +#include + #include "jni.h" namespace android { diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index ecfaec22de59..f670cf97e0c2 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -235,12 +235,10 @@ cc_defaults { "renderthread/RenderProxy.cpp", "renderthread/RenderThread.cpp", "service/GraphicsStatsService.cpp", - "surfacetexture/EGLConsumer.cpp", - "surfacetexture/ImageConsumer.cpp", - "surfacetexture/SurfaceTexture.cpp", "thread/CommonPool.cpp", "utils/GLUtils.cpp", "utils/StringUtils.cpp", + "AutoBackendTextureRelease.cpp", "DeferredLayerUpdater.cpp", "DeviceInfo.cpp", "FrameInfo.cpp", diff --git a/libs/hwui/AutoBackendTextureRelease.cpp b/libs/hwui/AutoBackendTextureRelease.cpp new file mode 100644 index 000000000000..72747e8fa543 --- /dev/null +++ b/libs/hwui/AutoBackendTextureRelease.cpp @@ -0,0 +1,91 @@ +/* + * Copyright 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. + */ + +#include "AutoBackendTextureRelease.h" + +#include "renderthread/RenderThread.h" +#include "utils/Color.h" +#include "utils/PaintUtils.h" + +using namespace android::uirenderer::renderthread; + +namespace android { +namespace uirenderer { + +AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer) { + AHardwareBuffer_Desc desc; + AHardwareBuffer_describe(buffer, &desc); + bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT); + GrBackendFormat backendFormat = + GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false); + mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture( + context, buffer, desc.width, desc.height, &mDeleteProc, &mUpdateProc, &mImageCtx, + createProtectedImage, backendFormat, false); +} + +void AutoBackendTextureRelease::unref(bool releaseImage) { + if (!RenderThread::isCurrent()) { + // EGLImage needs to be destroyed on RenderThread to prevent memory leak. + // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not + // thread safe. + RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); }); + return; + } + + if (releaseImage) { + mImage.reset(); + } + + mUsageCount--; + if (mUsageCount <= 0) { + if (mBackendTexture.isValid()) { + mDeleteProc(mImageCtx); + mBackendTexture = {}; + } + delete this; + } +} + +// releaseProc is invoked by SkImage, when texture is no longer in use. +// "releaseContext" contains an "AutoBackendTextureRelease*". +static void releaseProc(SkImage::ReleaseContext releaseContext) { + AutoBackendTextureRelease* textureRelease = + reinterpret_cast(releaseContext); + textureRelease->unref(false); +} + +void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer, android_dataspace dataspace, + GrContext* context) { + AHardwareBuffer_Desc desc; + AHardwareBuffer_describe(buffer, &desc); + SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format); + mImage = SkImage::MakeFromTexture( + context, mBackendTexture, kTopLeft_GrSurfaceOrigin, colorType, kPremul_SkAlphaType, + uirenderer::DataSpaceToColorSpace(dataspace), releaseProc, this); + if (mImage.get()) { + // The following ref will be counteracted by releaseProc, when SkImage is discarded. + ref(); + } +} + +void AutoBackendTextureRelease::newBufferContent(GrContext* context) { + if (mBackendTexture.isValid()) { + mUpdateProc(mImageCtx, context); + } +} + +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/AutoBackendTextureRelease.h b/libs/hwui/AutoBackendTextureRelease.h new file mode 100644 index 000000000000..acdd63cb7921 --- /dev/null +++ b/libs/hwui/AutoBackendTextureRelease.h @@ -0,0 +1,67 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace android { +namespace uirenderer { + +/** + * AutoBackendTextureRelease manages EglImage/VkImage lifetime. It is a ref-counted object + * that keeps GPU resources alive until the last SkImage object using them is destroyed. + */ +class AutoBackendTextureRelease final { +public: + AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer); + + const GrBackendTexture& getTexture() const { return mBackendTexture; } + + // Only called on the RenderThread, so it need not be thread-safe. + void ref() { mUsageCount++; } + + void unref(bool releaseImage); + + inline sk_sp getImage() const { return mImage; } + + void makeImage(AHardwareBuffer* buffer, android_dataspace dataspace, GrContext* context); + + void newBufferContent(GrContext* context); + +private: + // The only way to invoke dtor is with unref, when mUsageCount is 0. + ~AutoBackendTextureRelease() {} + + GrBackendTexture mBackendTexture; + GrAHardwareBufferUtils::DeleteImageProc mDeleteProc; + GrAHardwareBufferUtils::UpdateImageProc mUpdateProc; + GrAHardwareBufferUtils::TexImageCtx mImageCtx; + + // Starting with refcount 1, because the first ref is held by SurfaceTexture. Additional refs + // are held by SkImages. + int mUsageCount = 1; + + // mImage is the SkImage created from mBackendTexture. + sk_sp mImage; +}; + +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index f300703e7e00..d6b516fd5cf4 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -18,8 +18,15 @@ #include #include +#include "AutoBackendTextureRelease.h" +#include "Matrix.h" +#include "Properties.h" #include "renderstate/RenderState.h" -#include "utils/PaintUtils.h" +#include "renderthread/EglManager.h" +#include "renderthread/RenderThread.h" +#include "renderthread/VulkanManager.h" + +using namespace android::uirenderer::renderthread; namespace android { namespace uirenderer { @@ -27,7 +34,6 @@ namespace uirenderer { DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState) : mRenderState(renderState) , mBlend(false) - , mSurfaceTexture(nullptr) , mTransform(nullptr) , mGLContextAttached(false) , mUpdateTexImage(false) @@ -41,14 +47,12 @@ DeferredLayerUpdater::~DeferredLayerUpdater() { destroyLayer(); } -void DeferredLayerUpdater::setSurfaceTexture(const sp& consumer) { - if (consumer.get() != mSurfaceTexture.get()) { - mSurfaceTexture = consumer; +void DeferredLayerUpdater::setSurfaceTexture(AutoTextureRelease&& consumer) { + mSurfaceTexture = std::move(consumer); - GLenum target = consumer->getCurrentTextureTarget(); - LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES, - "set unsupported SurfaceTexture with target %x", target); - } + GLenum target = ASurfaceTexture_getCurrentTextureTarget(mSurfaceTexture.get()); + LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES, + "set unsupported SurfaceTexture with target %x", target); } void DeferredLayerUpdater::onContextDestroyed() { @@ -61,13 +65,15 @@ void DeferredLayerUpdater::destroyLayer() { } if (mSurfaceTexture.get() && mGLContextAttached) { - mSurfaceTexture->detachFromView(); + ASurfaceTexture_releaseConsumerOwnership(mSurfaceTexture.get()); mGLContextAttached = false; } mLayer->postDecStrong(); mLayer = nullptr; + + mImageSlots.clear(); } void DeferredLayerUpdater::setPaint(const SkPaint* paint) { @@ -80,6 +86,35 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) { } } +static status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, EGLDisplay* display, + int* releaseFence, void* handle) { + *display = EGL_NO_DISPLAY; + RenderState* renderState = (RenderState*)handle; + status_t err; + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { + EglManager& eglManager = renderState->getRenderThread().eglManager(); + *display = eglManager.eglDisplay(); + err = eglManager.createReleaseFence(useFenceSync, eglFence, releaseFence); + } else { + err = renderState->getRenderThread().vulkanManager().createReleaseFence( + releaseFence, renderState->getRenderThread().getGrContext()); + } + return err; +} + +static status_t fenceWait(int fence, void* handle) { + // Wait on the producer fence for the buffer to be ready. + status_t err; + RenderState* renderState = (RenderState*)handle; + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { + err = renderState->getRenderThread().eglManager().fenceWait(fence); + } else { + err = renderState->getRenderThread().vulkanManager().fenceWait( + fence, renderState->getRenderThread().getGrContext()); + } + return err; +} + void DeferredLayerUpdater::apply() { if (!mLayer) { mLayer = new Layer(mRenderState, mColorFilter, mAlpha, mMode); @@ -92,24 +127,33 @@ void DeferredLayerUpdater::apply() { if (!mGLContextAttached) { mGLContextAttached = true; mUpdateTexImage = true; - mSurfaceTexture->attachToView(); + ASurfaceTexture_takeConsumerOwnership(mSurfaceTexture.get()); } if (mUpdateTexImage) { mUpdateTexImage = false; - sk_sp layerImage; - SkMatrix textureTransform; - bool queueEmpty = true; - // If the SurfaceTexture queue is in synchronous mode, need to discard all - // but latest frame. Since we can't tell which mode it is in, - // do this unconditionally. - do { - layerImage = mSurfaceTexture->dequeueImage(textureTransform, &queueEmpty, - mRenderState); - } while (layerImage.get() && (!queueEmpty)); - if (layerImage.get()) { - // force filtration if buffer size != layer size - bool forceFilter = mWidth != layerImage->width() || mHeight != layerImage->height(); - updateLayer(forceFilter, textureTransform, layerImage); + float transformMatrix[16]; + android_dataspace dataspace; + int slot; + bool newContent = false; + // Note: ASurfaceTexture_dequeueBuffer discards all but the last frame. This + // is necessary if the SurfaceTexture queue is in synchronous mode, and we + // cannot tell which mode it is in. + AHardwareBuffer* hardwareBuffer = ASurfaceTexture_dequeueBuffer( + mSurfaceTexture.get(), &slot, &dataspace, transformMatrix, &newContent, + createReleaseFence, fenceWait, &mRenderState); + + if (hardwareBuffer) { + sk_sp layerImage = mImageSlots[slot].createIfNeeded( + hardwareBuffer, dataspace, newContent, + mRenderState.getRenderThread().getGrContext()); + if (layerImage.get()) { + SkMatrix textureTransform; + mat4(transformMatrix).copyTo(textureTransform); + // force filtration if buffer size != layer size + bool forceFilter = + mWidth != layerImage->width() || mHeight != layerImage->height(); + updateLayer(forceFilter, textureTransform, layerImage); + } } } @@ -121,7 +165,7 @@ void DeferredLayerUpdater::apply() { } void DeferredLayerUpdater::updateLayer(bool forceFilter, const SkMatrix& textureTransform, - const sk_sp& layerImage) { + const sk_sp& layerImage) { mLayer->setBlend(mBlend); mLayer->setForceFilter(forceFilter); mLayer->setSize(mWidth, mHeight); @@ -136,5 +180,42 @@ void DeferredLayerUpdater::detachSurfaceTexture() { } } +sk_sp DeferredLayerUpdater::ImageSlot::createIfNeeded(AHardwareBuffer* buffer, + android_dataspace dataspace, + bool forceCreate, + GrContext* context) { + if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace || + forceCreate || mBuffer != buffer) { + if (buffer != mBuffer) { + clear(); + } + + if (!buffer) { + return nullptr; + } + + if (!mTextureRelease) { + mTextureRelease = new AutoBackendTextureRelease(context, buffer); + } else { + mTextureRelease->newBufferContent(context); + } + + mDataspace = dataspace; + mBuffer = buffer; + mTextureRelease->makeImage(buffer, dataspace, context); + } + return mTextureRelease ? mTextureRelease->getImage() : nullptr; +} + +void DeferredLayerUpdater::ImageSlot::clear() { + if (mTextureRelease) { + // The following unref counteracts the initial mUsageCount of 1, set by default initializer. + mTextureRelease->unref(true); + mTextureRelease = nullptr; + } + + mBuffer = nullptr; +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index 1491f99402ba..289f65c22ad3 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -19,21 +19,26 @@ #include #include #include +#include #include +// TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead. +#include + #include -#include -#include +#include -#include "renderstate/RenderState.h" -#include "surfacetexture/SurfaceTexture.h" #include "Layer.h" #include "Rect.h" +#include "renderstate/RenderState.h" namespace android { namespace uirenderer { +class AutoBackendTextureRelease; class RenderState; +typedef std::unique_ptr AutoTextureRelease; + // Container to hold the properties a layer should be set to at the start // of a render pass class DeferredLayerUpdater : public VirtualLightRefBase, public IGpuContextCallback { @@ -64,7 +69,7 @@ public: return false; } - ANDROID_API void setSurfaceTexture(const sp& consumer); + ANDROID_API void setSurfaceTexture(AutoTextureRelease&& consumer); ANDROID_API void updateTexImage() { mUpdateTexImage = true; } @@ -92,6 +97,39 @@ protected: void onContextDestroyed() override; private: + /** + * ImageSlot contains the information and object references that + * DeferredLayerUpdater maintains about a slot. Slot id comes from + * ASurfaceTexture_dequeueBuffer. Usually there are at most 3 slots active at a time. + */ + class ImageSlot { + public: + ~ImageSlot() { clear(); } + + sk_sp createIfNeeded(AHardwareBuffer* buffer, android_dataspace dataspace, + bool forceCreate, GrContext* context); + + private: + void clear(); + + // the dataspace associated with the current image + android_dataspace mDataspace = HAL_DATASPACE_UNKNOWN; + + AHardwareBuffer* mBuffer = nullptr; + + /** + * mTextureRelease may outlive DeferredLayerUpdater, if the last ref is held by an SkImage. + * DeferredLayerUpdater holds one ref to mTextureRelease, which is decremented by "clear". + */ + AutoBackendTextureRelease* mTextureRelease = nullptr; + }; + + /** + * DeferredLayerUpdater stores the SkImages that have been allocated by the BufferQueue + * for each buffer slot. + */ + std::map mImageSlots; + RenderState& mRenderState; // Generic properties @@ -101,7 +139,7 @@ private: sk_sp mColorFilter; int mAlpha = 255; SkBlendMode mMode = SkBlendMode::kSrcOver; - sp mSurfaceTexture; + AutoTextureRelease mSurfaceTexture; SkMatrix* mTransform; bool mGLContextAttached; bool mUpdateTexImage; diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 12021641518c..eb469a810358 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -16,23 +16,23 @@ #include "EglManager.h" +#include +#include #include #include #include +#include +#include #include -#include "utils/Color.h" -#include "utils/StringUtils.h" - -#include "Frame.h" -#include "Properties.h" - -#include -#include -#include #include #include +#include "Frame.h" +#include "Properties.h" +#include "utils/Color.h" +#include "utils/StringUtils.h" + #define GLES_VERSION 2 // Android-specific addition that is used to show when frames began in systrace @@ -508,7 +508,21 @@ bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) { return preserved; } -status_t EglManager::fenceWait(sp& fence) { +static status_t waitForeverOnFence(int fence, const char* logname) { + ATRACE_CALL(); + if (fence == -1) { + return NO_ERROR; + } + constexpr int warningTimeout = 3000; + int err = sync_wait(fence, warningTimeout); + if (err < 0 && errno == ETIME) { + ALOGE("%s: fence %d didn't signal in %d ms", logname, fence, warningTimeout); + err = sync_wait(fence, -1); + } + return err < 0 ? -errno : status_t(NO_ERROR); +} + +status_t EglManager::fenceWait(int fence) { if (!hasEglContext()) { ALOGE("EglManager::fenceWait: EGLDisplay not initialized"); return INVALID_OPERATION; @@ -518,7 +532,7 @@ status_t EglManager::fenceWait(sp& fence) { SyncFeatures::getInstance().useNativeFenceSync()) { // Block GPU on the fence. // Create an EGLSyncKHR from the current fence. - int fenceFd = fence->dup(); + int fenceFd = ::dup(fence); if (fenceFd == -1) { ALOGE("EglManager::fenceWait: error dup'ing fence fd: %d", errno); return -errno; @@ -543,7 +557,7 @@ status_t EglManager::fenceWait(sp& fence) { } } else { // Block CPU on the fence. - status_t err = fence->waitForever("EglManager::fenceWait"); + status_t err = waitForeverOnFence(fence, "EglManager::fenceWait"); if (err != NO_ERROR) { ALOGE("EglManager::fenceWait: error waiting for fence: %d", err); return err; @@ -552,8 +566,8 @@ status_t EglManager::fenceWait(sp& fence) { return OK; } -status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, - sp& nativeFence) { +status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, int* nativeFence) { + *nativeFence = -1; if (!hasEglContext()) { ALOGE("EglManager::createReleaseFence: EGLDisplay not initialized"); return INVALID_OPERATION; @@ -574,7 +588,7 @@ status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, eglGetError()); return UNKNOWN_ERROR; } - nativeFence = new Fence(fenceFd); + *nativeFence = fenceFd; *eglFence = EGL_NO_SYNC_KHR; } else if (useFenceSync && SyncFeatures::getInstance().useFenceSync()) { if (*eglFence != EGL_NO_SYNC_KHR) { diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index 27d41d26a73a..a893e245b214 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -21,9 +21,9 @@ #include #include #include -#include #include #include + #include "IRenderPipeline.h" #include "utils/Result.h" @@ -74,11 +74,11 @@ public: // Inserts a wait on fence command into the OpenGL ES command stream. If EGL extension // support is missing, block the CPU on the fence. - status_t fenceWait(sp& fence); + status_t fenceWait(int fence); // Creates a fence that is signaled, when all the pending GL commands are flushed. // Depending on installed extensions, the result is either Android native fence or EGL fence. - status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, sp& nativeFence); + status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, int* nativeFence); private: enum class SwapBehavior { diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index bdd80721c4f3..da79e97a6ceb 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -17,33 +17,32 @@ #ifndef RENDERTHREAD_H_ #define RENDERTHREAD_H_ -#include "RenderTask.h" - -#include "CacheManager.h" -#include "ProfileDataContainer.h" -#include "TimeLord.h" -#include "WebViewFunctorManager.h" -#include "thread/ThreadBase.h" -#include "utils/TimeUtils.h" - #include #include #include +#include #include #include -#include #include #include #include +#include "CacheManager.h" +#include "ProfileDataContainer.h" +#include "RenderTask.h" +#include "TimeLord.h" +#include "WebViewFunctorManager.h" +#include "thread/ThreadBase.h" +#include "utils/TimeUtils.h" + namespace android { class Bitmap; -class AutoBackendTextureRelease; namespace uirenderer { +class AutoBackendTextureRelease; class Readback; class RenderState; class TestUtils; @@ -137,7 +136,7 @@ private: friend class DispatchFrameCallbacks; friend class RenderProxy; friend class DummyVsyncSource; - friend class android::AutoBackendTextureRelease; + friend class android::uirenderer::AutoBackendTextureRelease; friend class android::uirenderer::TestUtils; friend class android::uirenderer::WebViewFunctor; friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler; diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 35abc57fbe57..a5355fc3499d 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -16,23 +16,22 @@ #include "VulkanManager.h" -#include #include #include - -#include "Properties.h" -#include "RenderThread.h" -#include "renderstate/RenderState.h" -#include "utils/FatVector.h" -#include "utils/TraceUtils.h" - #include #include #include #include +#include #include #include +#include "Properties.h" +#include "RenderThread.h" +#include "renderstate/RenderState.h" +#include "utils/FatVector.h" +#include "utils/TraceUtils.h" + namespace android { namespace uirenderer { namespace renderthread { @@ -482,7 +481,7 @@ struct DestroySemaphoreInfo { int mRefs = 2; DestroySemaphoreInfo(PFN_vkDestroySemaphore destroyFunction, VkDevice device, - VkSemaphore semaphore) + VkSemaphore semaphore) : mDestroyFunction(destroyFunction), mDevice(device), mSemaphore(semaphore) {} }; @@ -524,12 +523,11 @@ void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) backendSemaphore.initVulkan(semaphore); int fenceFd = -1; - DestroySemaphoreInfo* destroyInfo = new DestroySemaphoreInfo(mDestroySemaphore, mDevice, - semaphore); - GrSemaphoresSubmitted submitted = - bufferInfo->skSurface->flush(SkSurface::BackendSurfaceAccess::kPresent, - kNone_GrFlushFlags, 1, &backendSemaphore, - destroy_semaphore, destroyInfo); + DestroySemaphoreInfo* destroyInfo = + new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore); + GrSemaphoresSubmitted submitted = bufferInfo->skSurface->flush( + SkSurface::BackendSurfaceAccess::kPresent, kNone_GrFlushFlags, 1, &backendSemaphore, + destroy_semaphore, destroyInfo); if (submitted == GrSemaphoresSubmitted::kYes) { VkSemaphoreGetFdInfoKHR getFdInfo; getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; @@ -571,14 +569,14 @@ VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode col *this, extraBuffers); } -status_t VulkanManager::fenceWait(sp& fence, GrContext* grContext) { +status_t VulkanManager::fenceWait(int fence, GrContext* grContext) { if (!hasVkContext()) { ALOGE("VulkanManager::fenceWait: VkDevice not initialized"); return INVALID_OPERATION; } // Block GPU on the fence. - int fenceFd = fence->dup(); + int fenceFd = ::dup(fence); if (fenceFd == -1) { ALOGE("VulkanManager::fenceWait: error dup'ing fence fd: %d", errno); return -errno; @@ -619,7 +617,8 @@ status_t VulkanManager::fenceWait(sp& fence, GrContext* grContext) { return OK; } -status_t VulkanManager::createReleaseFence(sp& nativeFence, GrContext* grContext) { +status_t VulkanManager::createReleaseFence(int* nativeFence, GrContext* grContext) { + *nativeFence = -1; if (!hasVkContext()) { ALOGE("VulkanManager::createReleaseFence: VkDevice not initialized"); return INVALID_OPERATION; @@ -644,14 +643,13 @@ status_t VulkanManager::createReleaseFence(sp& nativeFence, GrContext* gr GrBackendSemaphore backendSemaphore; backendSemaphore.initVulkan(semaphore); - DestroySemaphoreInfo* destroyInfo = new DestroySemaphoreInfo(mDestroySemaphore, mDevice, - semaphore); + DestroySemaphoreInfo* destroyInfo = + new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore); // Even if Skia fails to submit the semaphore, it will still call the destroy_semaphore callback // which will remove its ref to the semaphore. The VulkanManager must still release its ref, // when it is done with the semaphore. - GrSemaphoresSubmitted submitted = - grContext->flush(kNone_GrFlushFlags, 1, &backendSemaphore, - destroy_semaphore, destroyInfo); + GrSemaphoresSubmitted submitted = grContext->flush(kNone_GrFlushFlags, 1, &backendSemaphore, + destroy_semaphore, destroyInfo); if (submitted == GrSemaphoresSubmitted::kNo) { ALOGE("VulkanManager::createReleaseFence: Failed to submit semaphore"); @@ -673,7 +671,7 @@ status_t VulkanManager::createReleaseFence(sp& nativeFence, GrContext* gr ALOGE("VulkanManager::createReleaseFence: Failed to get semaphore Fd"); return INVALID_OPERATION; } - nativeFence = new Fence(fenceFd); + *nativeFence = fenceFd; return OK; } diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index 4c6a75504cd0..8b19f13fdfb9 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -20,14 +20,13 @@ #if !defined(VK_USE_PLATFORM_ANDROID_KHR) #define VK_USE_PLATFORM_ANDROID_KHR #endif -#include - #include #include -#include #include #include #include +#include + #include "Frame.h" #include "IRenderPipeline.h" #include "VulkanSurface.h" @@ -71,11 +70,11 @@ public: void destroy(); // Inserts a wait on fence command into the Vulkan command buffer. - status_t fenceWait(sp& fence, GrContext* grContext); + status_t fenceWait(int fence, GrContext* grContext); // Creates a fence that is signaled when all the pending Vulkan commands are finished on the // GPU. - status_t createReleaseFence(sp& nativeFence, GrContext* grContext); + status_t createReleaseFence(int* nativeFence, GrContext* grContext); // Returned pointers are owned by VulkanManager. // An instance of VkFunctorInitParams returned from getVkFunctorInitParams refers to diff --git a/libs/hwui/surfacetexture/EGLConsumer.cpp b/libs/hwui/surfacetexture/EGLConsumer.cpp deleted file mode 100644 index 85b3917809fa..000000000000 --- a/libs/hwui/surfacetexture/EGLConsumer.cpp +++ /dev/null @@ -1,675 +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. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "EGLConsumer.h" -#include "SurfaceTexture.h" - -#include -#include -#include - -#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content" -#define EGL_PROTECTED_CONTENT_EXT 0x32C0 - -namespace android { - -// Macros for including the SurfaceTexture name in log messages -#define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.string(), ##__VA_ARGS__) -#define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.string(), ##__VA_ARGS__) -#define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.string(), ##__VA_ARGS__) -#define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) - -static const struct { - uint32_t width, height; - char const* bits; -} kDebugData = {15, 12, - "_______________" - "_______________" - "_____XX_XX_____" - "__X_X_____X_X__" - "__X_XXXXXXX_X__" - "__XXXXXXXXXXX__" - "___XX_XXX_XX___" - "____XXXXXXX____" - "_____X___X_____" - "____X_____X____" - "_______________" - "_______________"}; - -Mutex EGLConsumer::sStaticInitLock; -sp EGLConsumer::sReleasedTexImageBuffer; - -static bool hasEglProtectedContentImpl() { - EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); - const char* exts = eglQueryString(dpy, EGL_EXTENSIONS); - size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR); - size_t extsLen = strlen(exts); - bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts); - bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen + 1); - bool atEnd = (cropExtLen + 1) < extsLen && - !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen + 1)); - bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " "); - return equal || atStart || atEnd || inMiddle; -} - -static bool hasEglProtectedContent() { - // Only compute whether the extension is present once the first time this - // function is called. - static bool hasIt = hasEglProtectedContentImpl(); - return hasIt; -} - -EGLConsumer::EGLConsumer() : mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT) {} - -status_t EGLConsumer::updateTexImage(SurfaceTexture& st) { - // Make sure the EGL state is the same as in previous calls. - status_t err = checkAndUpdateEglStateLocked(st); - if (err != NO_ERROR) { - return err; - } - - BufferItem item; - - // Acquire the next buffer. - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - err = st.acquireBufferLocked(&item, 0); - if (err != NO_ERROR) { - if (err == BufferQueue::NO_BUFFER_AVAILABLE) { - // We always bind the texture even if we don't update its contents. - EGC_LOGV("updateTexImage: no buffers were available"); - glBindTexture(st.mTexTarget, st.mTexName); - err = NO_ERROR; - } else { - EGC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err); - } - return err; - } - - // Release the previous buffer. - err = updateAndReleaseLocked(item, nullptr, st); - if (err != NO_ERROR) { - // We always bind the texture. - glBindTexture(st.mTexTarget, st.mTexName); - return err; - } - - // Bind the new buffer to the GL texture, and wait until it's ready. - return bindTextureImageLocked(st); -} - -status_t EGLConsumer::releaseTexImage(SurfaceTexture& st) { - // Make sure the EGL state is the same as in previous calls. - status_t err = NO_ERROR; - - // if we're detached, no need to validate EGL's state -- we won't use it. - if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) { - err = checkAndUpdateEglStateLocked(st, true); - if (err != NO_ERROR) { - return err; - } - } - - // Update the EGLConsumer state. - int buf = st.mCurrentTexture; - if (buf != BufferQueue::INVALID_BUFFER_SLOT) { - EGC_LOGV("releaseTexImage: (slot=%d, mOpMode=%d)", buf, (int)st.mOpMode); - - // if we're detached, we just use the fence that was created in detachFromContext() - // so... basically, nothing more to do here. - if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) { - // Do whatever sync ops we need to do before releasing the slot. - err = syncForReleaseLocked(mEglDisplay, st); - if (err != NO_ERROR) { - EGC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err); - return err; - } - } - - err = st.releaseBufferLocked(buf, st.mSlots[buf].mGraphicBuffer, mEglDisplay, - EGL_NO_SYNC_KHR); - if (err < NO_ERROR) { - EGC_LOGE("releaseTexImage: failed to release buffer: %s (%d)", strerror(-err), err); - return err; - } - - if (mReleasedTexImage == nullptr) { - mReleasedTexImage = new EglImage(getDebugTexImageBuffer()); - } - - st.mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; - mCurrentTextureImage = mReleasedTexImage; - st.mCurrentCrop.makeInvalid(); - st.mCurrentTransform = 0; - st.mCurrentTimestamp = 0; - st.mCurrentDataSpace = HAL_DATASPACE_UNKNOWN; - st.mCurrentFence = Fence::NO_FENCE; - st.mCurrentFenceTime = FenceTime::NO_FENCE; - - // detached, don't touch the texture (and we may not even have an - // EGLDisplay here. - if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) { - // This binds a dummy buffer (mReleasedTexImage). - status_t result = bindTextureImageLocked(st); - if (result != NO_ERROR) { - return result; - } - } - } - - return NO_ERROR; -} - -sp EGLConsumer::getDebugTexImageBuffer() { - Mutex::Autolock _l(sStaticInitLock); - if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) { - // The first time, create the debug texture in case the application - // continues to use it. - sp buffer = new GraphicBuffer( - kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888, - GraphicBuffer::USAGE_SW_WRITE_RARELY, "[EGLConsumer debug texture]"); - uint32_t* bits; - buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast(&bits)); - uint32_t stride = buffer->getStride(); - uint32_t height = buffer->getHeight(); - memset(bits, 0, stride * height * 4); - for (uint32_t y = 0; y < kDebugData.height; y++) { - for (uint32_t x = 0; x < kDebugData.width; x++) { - bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ? 0xFF000000 - : 0xFFFFFFFF; - } - bits += stride; - } - buffer->unlock(); - sReleasedTexImageBuffer = buffer; - } - return sReleasedTexImageBuffer; -} - -void EGLConsumer::onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st) { - // If item->mGraphicBuffer is not null, this buffer has not been acquired - // before, so any prior EglImage created is using a stale buffer. This - // replaces any old EglImage with a new one (using the new buffer). - int slot = item->mSlot; - if (item->mGraphicBuffer != nullptr || mEglSlots[slot].mEglImage.get() == nullptr) { - mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer); - } -} - -void EGLConsumer::onReleaseBufferLocked(int buf) { - mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR; -} - -status_t EGLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease, - SurfaceTexture& st) { - status_t err = NO_ERROR; - - int slot = item.mSlot; - - if (st.mOpMode != SurfaceTexture::OpMode::attachedToGL) { - EGC_LOGE( - "updateAndRelease: EGLConsumer is not attached to an OpenGL " - "ES context"); - st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); - return INVALID_OPERATION; - } - - // Confirm state. - err = checkAndUpdateEglStateLocked(st); - if (err != NO_ERROR) { - st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); - return err; - } - - // Ensure we have a valid EglImageKHR for the slot, creating an EglImage - // if nessessary, for the gralloc buffer currently in the slot in - // ConsumerBase. - // We may have to do this even when item.mGraphicBuffer == NULL (which - // means the buffer was previously acquired). - err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay); - if (err != NO_ERROR) { - EGC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay, - slot); - st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); - return UNKNOWN_ERROR; - } - - // Do whatever sync ops we need to do before releasing the old slot. - if (slot != st.mCurrentTexture) { - err = syncForReleaseLocked(mEglDisplay, st); - if (err != NO_ERROR) { - // Release the buffer we just acquired. It's not safe to - // release the old buffer, so instead we just drop the new frame. - // As we are still under lock since acquireBuffer, it is safe to - // release by slot. - st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, - EGL_NO_SYNC_KHR); - return err; - } - } - - EGC_LOGV( - "updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", st.mCurrentTexture, - mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : nullptr, - slot, st.mSlots[slot].mGraphicBuffer->handle); - - // Hang onto the pointer so that it isn't freed in the call to - // releaseBufferLocked() if we're in shared buffer mode and both buffers are - // the same. - sp nextTextureImage = mEglSlots[slot].mEglImage; - - // release old buffer - if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - if (pendingRelease == nullptr) { - status_t status = st.releaseBufferLocked( - st.mCurrentTexture, mCurrentTextureImage->graphicBuffer(), mEglDisplay, - mEglSlots[st.mCurrentTexture].mEglFence); - if (status < NO_ERROR) { - EGC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), - status); - err = status; - // keep going, with error raised [?] - } - } else { - pendingRelease->currentTexture = st.mCurrentTexture; - pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer(); - pendingRelease->display = mEglDisplay; - pendingRelease->fence = mEglSlots[st.mCurrentTexture].mEglFence; - pendingRelease->isPending = true; - } - } - - // Update the EGLConsumer state. - st.mCurrentTexture = slot; - mCurrentTextureImage = nextTextureImage; - st.mCurrentCrop = item.mCrop; - st.mCurrentTransform = item.mTransform; - st.mCurrentScalingMode = item.mScalingMode; - st.mCurrentTimestamp = item.mTimestamp; - st.mCurrentDataSpace = item.mDataSpace; - st.mCurrentFence = item.mFence; - st.mCurrentFenceTime = item.mFenceTime; - st.mCurrentFrameNumber = item.mFrameNumber; - - st.computeCurrentTransformMatrixLocked(); - - return err; -} - -status_t EGLConsumer::bindTextureImageLocked(SurfaceTexture& st) { - if (mEglDisplay == EGL_NO_DISPLAY) { - ALOGE("bindTextureImage: invalid display"); - return INVALID_OPERATION; - } - - GLenum error; - while ((error = glGetError()) != GL_NO_ERROR) { - EGC_LOGW("bindTextureImage: clearing GL error: %#04x", error); - } - - glBindTexture(st.mTexTarget, st.mTexName); - if (st.mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) { - EGC_LOGE("bindTextureImage: no currently-bound texture"); - return NO_INIT; - } - - status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay); - if (err != NO_ERROR) { - EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay, - st.mCurrentTexture); - return UNKNOWN_ERROR; - } - mCurrentTextureImage->bindToTextureTarget(st.mTexTarget); - - // In the rare case that the display is terminated and then initialized - // again, we can't detect that the display changed (it didn't), but the - // image is invalid. In this case, repeat the exact same steps while - // forcing the creation of a new image. - if ((error = glGetError()) != GL_NO_ERROR) { - glBindTexture(st.mTexTarget, st.mTexName); - status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, true); - if (result != NO_ERROR) { - EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay, - st.mCurrentTexture); - return UNKNOWN_ERROR; - } - mCurrentTextureImage->bindToTextureTarget(st.mTexTarget); - if ((error = glGetError()) != GL_NO_ERROR) { - EGC_LOGE("bindTextureImage: error binding external image: %#04x", error); - return UNKNOWN_ERROR; - } - } - - // Wait for the new buffer to be ready. - return doGLFenceWaitLocked(st); -} - -status_t EGLConsumer::checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck) { - EGLDisplay dpy = eglGetCurrentDisplay(); - EGLContext ctx = eglGetCurrentContext(); - - if (!contextCheck) { - // if this is the first time we're called, mEglDisplay/mEglContext have - // never been set, so don't error out (below). - if (mEglDisplay == EGL_NO_DISPLAY) { - mEglDisplay = dpy; - } - if (mEglContext == EGL_NO_CONTEXT) { - mEglContext = ctx; - } - } - - if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) { - EGC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay"); - return INVALID_OPERATION; - } - - if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) { - EGC_LOGE("checkAndUpdateEglState: invalid current EGLContext"); - return INVALID_OPERATION; - } - - mEglDisplay = dpy; - mEglContext = ctx; - return NO_ERROR; -} - -status_t EGLConsumer::detachFromContext(SurfaceTexture& st) { - EGLDisplay dpy = eglGetCurrentDisplay(); - EGLContext ctx = eglGetCurrentContext(); - - if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) { - EGC_LOGE("detachFromContext: invalid current EGLDisplay"); - return INVALID_OPERATION; - } - - if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) { - EGC_LOGE("detachFromContext: invalid current EGLContext"); - return INVALID_OPERATION; - } - - if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) { - status_t err = syncForReleaseLocked(dpy, st); - if (err != OK) { - return err; - } - - glDeleteTextures(1, &st.mTexName); - } - - mEglDisplay = EGL_NO_DISPLAY; - mEglContext = EGL_NO_CONTEXT; - - return OK; -} - -status_t EGLConsumer::attachToContext(uint32_t tex, SurfaceTexture& st) { - // Initialize mCurrentTextureImage if there is a current buffer from past attached state. - int slot = st.mCurrentTexture; - if (slot != BufferItem::INVALID_BUFFER_SLOT) { - if (!mEglSlots[slot].mEglImage.get()) { - mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer); - } - mCurrentTextureImage = mEglSlots[slot].mEglImage; - } - - EGLDisplay dpy = eglGetCurrentDisplay(); - EGLContext ctx = eglGetCurrentContext(); - - if (dpy == EGL_NO_DISPLAY) { - EGC_LOGE("attachToContext: invalid current EGLDisplay"); - return INVALID_OPERATION; - } - - if (ctx == EGL_NO_CONTEXT) { - EGC_LOGE("attachToContext: invalid current EGLContext"); - return INVALID_OPERATION; - } - - // We need to bind the texture regardless of whether there's a current - // buffer. - glBindTexture(st.mTexTarget, GLuint(tex)); - - mEglDisplay = dpy; - mEglContext = ctx; - st.mTexName = tex; - st.mOpMode = SurfaceTexture::OpMode::attachedToGL; - - if (mCurrentTextureImage != nullptr) { - // This may wait for a buffer a second time. This is likely required if - // this is a different context, since otherwise the wait could be skipped - // by bouncing through another context. For the same context the extra - // wait is redundant. - status_t err = bindTextureImageLocked(st); - if (err != NO_ERROR) { - return err; - } - } - - return OK; -} - -status_t EGLConsumer::syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st) { - EGC_LOGV("syncForReleaseLocked"); - - if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - if (SyncFeatures::getInstance().useNativeFenceSync()) { - EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); - if (sync == EGL_NO_SYNC_KHR) { - EGC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError()); - return UNKNOWN_ERROR; - } - glFlush(); - int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync); - eglDestroySyncKHR(dpy, sync); - if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { - EGC_LOGE( - "syncForReleaseLocked: error dup'ing native fence " - "fd: %#x", - eglGetError()); - return UNKNOWN_ERROR; - } - sp fence(new Fence(fenceFd)); - status_t err = st.addReleaseFenceLocked(st.mCurrentTexture, - mCurrentTextureImage->graphicBuffer(), fence); - if (err != OK) { - EGC_LOGE( - "syncForReleaseLocked: error adding release fence: " - "%s (%d)", - strerror(-err), err); - return err; - } - } else if (st.mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) { - EGLSyncKHR fence = mEglSlots[st.mCurrentTexture].mEglFence; - if (fence != EGL_NO_SYNC_KHR) { - // There is already a fence for the current slot. We need to - // wait on that before replacing it with another fence to - // ensure that all outstanding buffer accesses have completed - // before the producer accesses it. - EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); - if (result == EGL_FALSE) { - EGC_LOGE( - "syncForReleaseLocked: error waiting for previous " - "fence: %#x", - eglGetError()); - return UNKNOWN_ERROR; - } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { - EGC_LOGE( - "syncForReleaseLocked: timeout waiting for previous " - "fence"); - return TIMED_OUT; - } - eglDestroySyncKHR(dpy, fence); - } - - // Create a fence for the outstanding accesses in the current - // OpenGL ES context. - fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr); - if (fence == EGL_NO_SYNC_KHR) { - EGC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError()); - return UNKNOWN_ERROR; - } - glFlush(); - mEglSlots[st.mCurrentTexture].mEglFence = fence; - } - } - - return OK; -} - -status_t EGLConsumer::doGLFenceWaitLocked(SurfaceTexture& st) const { - EGLDisplay dpy = eglGetCurrentDisplay(); - EGLContext ctx = eglGetCurrentContext(); - - if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) { - EGC_LOGE("doGLFenceWait: invalid current EGLDisplay"); - return INVALID_OPERATION; - } - - if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) { - EGC_LOGE("doGLFenceWait: invalid current EGLContext"); - return INVALID_OPERATION; - } - - if (st.mCurrentFence->isValid()) { - if (SyncFeatures::getInstance().useWaitSync() && - SyncFeatures::getInstance().useNativeFenceSync()) { - // Create an EGLSyncKHR from the current fence. - int fenceFd = st.mCurrentFence->dup(); - if (fenceFd == -1) { - EGC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno); - return -errno; - } - EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE}; - EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); - if (sync == EGL_NO_SYNC_KHR) { - close(fenceFd); - EGC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError()); - return UNKNOWN_ERROR; - } - - // XXX: The spec draft is inconsistent as to whether this should - // return an EGLint or void. Ignore the return value for now, as - // it's not strictly needed. - eglWaitSyncKHR(dpy, sync, 0); - EGLint eglErr = eglGetError(); - eglDestroySyncKHR(dpy, sync); - if (eglErr != EGL_SUCCESS) { - EGC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr); - return UNKNOWN_ERROR; - } - } else { - status_t err = st.mCurrentFence->waitForever("EGLConsumer::doGLFenceWaitLocked"); - if (err != NO_ERROR) { - EGC_LOGE("doGLFenceWait: error waiting for fence: %d", err); - return err; - } - } - } - - return NO_ERROR; -} - -void EGLConsumer::onFreeBufferLocked(int slotIndex) { - mEglSlots[slotIndex].mEglImage.clear(); -} - -void EGLConsumer::onAbandonLocked() { - mCurrentTextureImage.clear(); -} - -EGLConsumer::EglImage::EglImage(sp graphicBuffer) - : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), mEglDisplay(EGL_NO_DISPLAY) {} - -EGLConsumer::EglImage::~EglImage() { - if (mEglImage != EGL_NO_IMAGE_KHR) { - if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { - ALOGE("~EglImage: eglDestroyImageKHR failed"); - } - eglTerminate(mEglDisplay); - } -} - -status_t EGLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, bool forceCreation) { - // If there's an image and it's no longer valid, destroy it. - bool haveImage = mEglImage != EGL_NO_IMAGE_KHR; - bool displayInvalid = mEglDisplay != eglDisplay; - if (haveImage && (displayInvalid || forceCreation)) { - if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { - ALOGE("createIfNeeded: eglDestroyImageKHR failed"); - } - eglTerminate(mEglDisplay); - mEglImage = EGL_NO_IMAGE_KHR; - mEglDisplay = EGL_NO_DISPLAY; - } - - // If there's no image, create one. - if (mEglImage == EGL_NO_IMAGE_KHR) { - mEglDisplay = eglDisplay; - mEglImage = createImage(mEglDisplay, mGraphicBuffer); - } - - // Fail if we can't create a valid image. - if (mEglImage == EGL_NO_IMAGE_KHR) { - mEglDisplay = EGL_NO_DISPLAY; - const sp& buffer = mGraphicBuffer; - ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d", - buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(), - buffer->getPixelFormat()); - return UNKNOWN_ERROR; - } - - return OK; -} - -void EGLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) { - glEGLImageTargetTexture2DOES(texTarget, static_cast(mEglImage)); -} - -EGLImageKHR EGLConsumer::EglImage::createImage(EGLDisplay dpy, - const sp& graphicBuffer) { - EGLClientBuffer cbuf = static_cast(graphicBuffer->getNativeBuffer()); - const bool createProtectedImage = - (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent(); - EGLint attrs[] = { - EGL_IMAGE_PRESERVED_KHR, - EGL_TRUE, - createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, - createProtectedImage ? EGL_TRUE : EGL_NONE, - EGL_NONE, - }; - eglInitialize(dpy, nullptr, nullptr); - EGLImageKHR image = - eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); - if (image == EGL_NO_IMAGE_KHR) { - EGLint error = eglGetError(); - ALOGE("error creating EGLImage: %#x", error); - eglTerminate(dpy); - } - return image; -} - -} // namespace android diff --git a/libs/hwui/surfacetexture/EGLConsumer.h b/libs/hwui/surfacetexture/EGLConsumer.h deleted file mode 100644 index 7dac3ef0f44a..000000000000 --- a/libs/hwui/surfacetexture/EGLConsumer.h +++ /dev/null @@ -1,311 +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. - */ - -#pragma once - -#include -#include - -#include - -#include -#include -#include - -namespace android { - -class SurfaceTexture; - -/* - * EGLConsumer implements the parts of SurfaceTexture that deal with - * textures attached to an GL context. - */ -class EGLConsumer { -public: - EGLConsumer(); - - /** - * updateTexImage acquires the most recently queued buffer, and sets the - * image contents of the target texture to it. - * - * This call may only be made while the OpenGL ES context to which the - * target texture belongs is bound to the calling thread. - * - * This calls doGLFenceWait to ensure proper synchronization. - */ - status_t updateTexImage(SurfaceTexture& st); - - /* - * releaseTexImage releases the texture acquired in updateTexImage(). - * This is intended to be used in single buffer mode. - * - * This call may only be made while the OpenGL ES context to which the - * target texture belongs is bound to the calling thread. - */ - status_t releaseTexImage(SurfaceTexture& st); - - /** - * detachFromContext detaches the EGLConsumer from the calling thread's - * current OpenGL ES context. This context must be the same as the context - * that was current for previous calls to updateTexImage. - * - * Detaching a EGLConsumer from an OpenGL ES context will result in the - * deletion of the OpenGL ES texture object into which the images were being - * streamed. After a EGLConsumer has been detached from the OpenGL ES - * context calls to updateTexImage will fail returning INVALID_OPERATION - * until the EGLConsumer is attached to a new OpenGL ES context using the - * attachToContext method. - */ - status_t detachFromContext(SurfaceTexture& st); - - /** - * attachToContext attaches a EGLConsumer that is currently in the - * 'detached' state to the current OpenGL ES context. A EGLConsumer is - * in the 'detached' state iff detachFromContext has successfully been - * called and no calls to attachToContext have succeeded since the last - * detachFromContext call. Calls to attachToContext made on a - * EGLConsumer that is not in the 'detached' state will result in an - * INVALID_OPERATION error. - * - * The tex argument specifies the OpenGL ES texture object name in the - * new context into which the image contents will be streamed. A successful - * call to attachToContext will result in this texture object being bound to - * the texture target and populated with the image contents that were - * current at the time of the last call to detachFromContext. - */ - status_t attachToContext(uint32_t tex, SurfaceTexture& st); - - /** - * onAcquireBufferLocked amends the ConsumerBase method to update the - * mEglSlots array in addition to the ConsumerBase behavior. - */ - void onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st); - - /** - * onReleaseBufferLocked amends the ConsumerBase method to update the - * mEglSlots array in addition to the ConsumerBase. - */ - void onReleaseBufferLocked(int slot); - - /** - * onFreeBufferLocked frees up the given buffer slot. If the slot has been - * initialized this will release the reference to the GraphicBuffer in that - * slot and destroy the EGLImage in that slot. Otherwise it has no effect. - */ - void onFreeBufferLocked(int slotIndex); - - /** - * onAbandonLocked amends the ConsumerBase method to clear - * mCurrentTextureImage in addition to the ConsumerBase behavior. - */ - void onAbandonLocked(); - -protected: - struct PendingRelease { - PendingRelease() - : isPending(false) - , currentTexture(-1) - , graphicBuffer() - , display(nullptr) - , fence(nullptr) {} - - bool isPending; - int currentTexture; - sp graphicBuffer; - EGLDisplay display; - EGLSyncKHR fence; - }; - - /** - * This releases the buffer in the slot referenced by mCurrentTexture, - * then updates state to refer to the BufferItem, which must be a - * newly-acquired buffer. If pendingRelease is not null, the parameters - * which would have been passed to releaseBufferLocked upon the successful - * completion of the method will instead be returned to the caller, so that - * it may call releaseBufferLocked itself later. - */ - status_t updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease, - SurfaceTexture& st); - - /** - * Binds mTexName and the current buffer to mTexTarget. Uses - * mCurrentTexture if it's set, mCurrentTextureImage if not. If the - * bind succeeds, this calls doGLFenceWait. - */ - status_t bindTextureImageLocked(SurfaceTexture& st); - - /** - * Gets the current EGLDisplay and EGLContext values, and compares them - * to mEglDisplay and mEglContext. If the fields have been previously - * set, the values must match; if not, the fields are set to the current - * values. - * The contextCheck argument is used to ensure that a GL context is - * properly set; when set to false, the check is not performed. - */ - status_t checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck = false); - - /** - * EglImage is a utility class for tracking and creating EGLImageKHRs. There - * is primarily just one image per slot, but there is also special cases: - * - For releaseTexImage, we use a debug image (mReleasedTexImage) - * - After freeBuffer, we must still keep the current image/buffer - * Reference counting EGLImages lets us handle all these cases easily while - * also only creating new EGLImages from buffers when required. - */ - class EglImage : public LightRefBase { - public: - EglImage(sp graphicBuffer); - - /** - * createIfNeeded creates an EGLImage if required (we haven't created - * one yet, or the EGLDisplay or crop-rect has changed). - */ - status_t createIfNeeded(EGLDisplay display, bool forceCreate = false); - - /** - * This calls glEGLImageTargetTexture2DOES to bind the image to the - * texture in the specified texture target. - */ - void bindToTextureTarget(uint32_t texTarget); - - const sp& graphicBuffer() { return mGraphicBuffer; } - const native_handle* graphicBufferHandle() { - return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle; - } - - private: - // Only allow instantiation using ref counting. - friend class LightRefBase; - virtual ~EglImage(); - - // createImage creates a new EGLImage from a GraphicBuffer. - EGLImageKHR createImage(EGLDisplay dpy, const sp& graphicBuffer); - - // Disallow copying - EglImage(const EglImage& rhs); - void operator=(const EglImage& rhs); - - // mGraphicBuffer is the buffer that was used to create this image. - sp mGraphicBuffer; - - // mEglImage is the EGLImage created from mGraphicBuffer. - EGLImageKHR mEglImage; - - // mEGLDisplay is the EGLDisplay that was used to create mEglImage. - EGLDisplay mEglDisplay; - - // mCropRect is the crop rectangle passed to EGL when mEglImage - // was created. - Rect mCropRect; - }; - - /** - * doGLFenceWaitLocked inserts a wait command into the OpenGL ES command - * stream to ensure that it is safe for future OpenGL ES commands to - * access the current texture buffer. - */ - status_t doGLFenceWaitLocked(SurfaceTexture& st) const; - - /** - * syncForReleaseLocked performs the synchronization needed to release the - * current slot from an OpenGL ES context. If needed it will set the - * current slot's fence to guard against a producer accessing the buffer - * before the outstanding accesses have completed. - */ - status_t syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st); - - /** - * returns a graphic buffer used when the texture image has been released - */ - static sp getDebugTexImageBuffer(); - - /** - * The default consumer usage flags that EGLConsumer always sets on its - * BufferQueue instance; these will be OR:d with any additional flags passed - * from the EGLConsumer user. In particular, EGLConsumer will always - * consume buffers as hardware textures. - */ - static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; - - /** - * mCurrentTextureImage is the EglImage/buffer of the current texture. It's - * possible that this buffer is not associated with any buffer slot, so we - * must track it separately in order to support the getCurrentBuffer method. - */ - sp mCurrentTextureImage; - - /** - * EGLSlot contains the information and object references that - * EGLConsumer maintains about a BufferQueue buffer slot. - */ - struct EglSlot { - EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {} - - /** - * mEglImage is the EGLImage created from mGraphicBuffer. - */ - sp mEglImage; - - /** - * mFence is the EGL sync object that must signal before the buffer - * associated with this buffer slot may be dequeued. It is initialized - * to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based - * on a compile-time option) set to a new sync object in updateTexImage. - */ - EGLSyncKHR mEglFence; - }; - - /** - * mEglDisplay is the EGLDisplay with which this EGLConsumer is currently - * associated. It is intialized to EGL_NO_DISPLAY and gets set to the - * current display when updateTexImage is called for the first time and when - * attachToContext is called. - */ - EGLDisplay mEglDisplay; - - /** - * mEglContext is the OpenGL ES context with which this EGLConsumer is - * currently associated. It is initialized to EGL_NO_CONTEXT and gets set - * to the current GL context when updateTexImage is called for the first - * time and when attachToContext is called. - */ - EGLContext mEglContext; - - /** - * mEGLSlots stores the buffers that have been allocated by the BufferQueue - * for each buffer slot. It is initialized to null pointers, and gets - * filled in with the result of BufferQueue::acquire when the - * client dequeues a buffer from a - * slot that has not yet been used. The buffer allocated to a slot will also - * be replaced if the requested buffer usage or geometry differs from that - * of the buffer allocated to a slot. - */ - EglSlot mEglSlots[BufferQueueDefs::NUM_BUFFER_SLOTS]; - - /** - * protects static initialization - */ - static Mutex sStaticInitLock; - - /** - * mReleasedTexImageBuffer is a dummy buffer used when in single buffer - * mode and releaseTexImage() has been called - */ - static sp sReleasedTexImageBuffer; - sp mReleasedTexImage; -}; - -} // namespace android diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp deleted file mode 100644 index 17ee17d5cd1d..000000000000 --- a/libs/hwui/surfacetexture/ImageConsumer.cpp +++ /dev/null @@ -1,299 +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. - */ - -#include "ImageConsumer.h" -#include -#include "Properties.h" -#include "SurfaceTexture.h" -#include "renderstate/RenderState.h" -#include "renderthread/EglManager.h" -#include "renderthread/RenderThread.h" -#include "renderthread/VulkanManager.h" -#include "utils/Color.h" -#include -#include - -// Macro for including the SurfaceTexture name in log messages -#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) - -using namespace android::uirenderer::renderthread; - -namespace android { - -void ImageConsumer::onFreeBufferLocked(int slotIndex) { - // This callback may be invoked on any thread. - mImageSlots[slotIndex].clear(); -} - -void ImageConsumer::onAcquireBufferLocked(BufferItem* item) { - // If item->mGraphicBuffer is not null, this buffer has not been acquired - // before, so any prior SkImage is created with a stale buffer. This resets the stale SkImage. - if (item->mGraphicBuffer != nullptr) { - mImageSlots[item->mSlot].clear(); - } -} - -void ImageConsumer::onReleaseBufferLocked(int buf) { - mImageSlots[buf].eglFence() = EGL_NO_SYNC_KHR; -} - -/** - * AutoBackendTextureRelease manages EglImage/VkImage lifetime. It is a ref-counted object - * that keeps GPU resources alive until the last SKImage object using them is destroyed. - */ -class AutoBackendTextureRelease { -public: - static void releaseProc(SkImage::ReleaseContext releaseContext); - - AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer); - - const GrBackendTexture& getTexture() const { return mBackendTexture; } - - void ref() { mUsageCount++; } - - void unref(bool releaseImage); - - inline sk_sp getImage() { return mImage; } - - void makeImage(sp& graphicBuffer, android_dataspace dataspace, - GrContext* context); - - void newBufferContent(GrContext* context); - -private: - // The only way to invoke dtor is with unref, when mUsageCount is 0. - ~AutoBackendTextureRelease() {} - - GrBackendTexture mBackendTexture; - GrAHardwareBufferUtils::DeleteImageProc mDeleteProc; - GrAHardwareBufferUtils::UpdateImageProc mUpdateProc; - GrAHardwareBufferUtils::TexImageCtx mImageCtx; - - // Starting with refcount 1, because the first ref is held by SurfaceTexture. Additional refs - // are held by SkImages. - int mUsageCount = 1; - - // mImage is the SkImage created from mBackendTexture. - sk_sp mImage; -}; - -AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer) { - bool createProtectedImage = - 0 != (buffer->getUsage() & GraphicBuffer::USAGE_PROTECTED); - GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat( - context, - reinterpret_cast(buffer), - buffer->getPixelFormat(), - false); - mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture( - context, - reinterpret_cast(buffer), - buffer->getWidth(), - buffer->getHeight(), - &mDeleteProc, - &mUpdateProc, - &mImageCtx, - createProtectedImage, - backendFormat, - false); -} - -void AutoBackendTextureRelease::unref(bool releaseImage) { - if (!RenderThread::isCurrent()) { - // EGLImage needs to be destroyed on RenderThread to prevent memory leak. - // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not - // thread safe. - RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); }); - return; - } - - if (releaseImage) { - mImage.reset(); - } - - mUsageCount--; - if (mUsageCount <= 0) { - if (mBackendTexture.isValid()) { - mDeleteProc(mImageCtx); - mBackendTexture = {}; - } - delete this; - } -} - -void AutoBackendTextureRelease::releaseProc(SkImage::ReleaseContext releaseContext) { - AutoBackendTextureRelease* textureRelease = - reinterpret_cast(releaseContext); - textureRelease->unref(false); -} - -void AutoBackendTextureRelease::makeImage(sp& graphicBuffer, - android_dataspace dataspace, GrContext* context) { - SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat( - graphicBuffer->getPixelFormat()); - mImage = SkImage::MakeFromTexture(context, - mBackendTexture, - kTopLeft_GrSurfaceOrigin, - colorType, - kPremul_SkAlphaType, - uirenderer::DataSpaceToColorSpace(dataspace), - releaseProc, - this); - if (mImage.get()) { - // The following ref will be counteracted by releaseProc, when SkImage is discarded. - ref(); - } -} - -void AutoBackendTextureRelease::newBufferContent(GrContext* context) { - if (mBackendTexture.isValid()) { - mUpdateProc(mImageCtx, context); - } -} - -void ImageConsumer::ImageSlot::createIfNeeded(sp graphicBuffer, - android_dataspace dataspace, bool forceCreate, - GrContext* context) { - if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace - || forceCreate) { - if (!graphicBuffer.get()) { - clear(); - return; - } - - if (!mTextureRelease) { - mTextureRelease = new AutoBackendTextureRelease(context, graphicBuffer.get()); - } else { - mTextureRelease->newBufferContent(context); - } - - mDataspace = dataspace; - mTextureRelease->makeImage(graphicBuffer, dataspace, context); - } -} - -void ImageConsumer::ImageSlot::clear() { - if (mTextureRelease) { - // The following unref counteracts the initial mUsageCount of 1, set by default initializer. - mTextureRelease->unref(true); - mTextureRelease = nullptr; - } -} - -sk_sp ImageConsumer::ImageSlot::getImage() { - return mTextureRelease ? mTextureRelease->getImage() : nullptr; -} - -sk_sp ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, - uirenderer::RenderState& renderState) { - BufferItem item; - status_t err; - err = st.acquireBufferLocked(&item, 0); - if (err != OK) { - if (err != BufferQueue::NO_BUFFER_AVAILABLE) { - IMG_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); - } else { - int slot = st.mCurrentTexture; - if (slot != BufferItem::INVALID_BUFFER_SLOT) { - *queueEmpty = true; - mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, - st.mCurrentDataSpace, false, renderState.getRenderThread().getGrContext()); - return mImageSlots[slot].getImage(); - } - } - return nullptr; - } - - int slot = item.mSlot; - if (item.mFence->isValid()) { - // Wait on the producer fence for the buffer to be ready. - if (uirenderer::Properties::getRenderPipelineType() == - uirenderer::RenderPipelineType::SkiaGL) { - err = renderState.getRenderThread().eglManager().fenceWait(item.mFence); - } else { - err = renderState.getRenderThread().vulkanManager().fenceWait( - item.mFence, renderState.getRenderThread().getGrContext()); - } - if (err != OK) { - st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY, - EGL_NO_SYNC_KHR); - return nullptr; - } - } - - // Release old buffer. - if (st.mCurrentTexture != BufferItem::INVALID_BUFFER_SLOT) { - // If needed, set the released slot's fence to guard against a producer accessing the - // buffer before the outstanding accesses have completed. - sp releaseFence; - EGLDisplay display = EGL_NO_DISPLAY; - if (uirenderer::Properties::getRenderPipelineType() == - uirenderer::RenderPipelineType::SkiaGL) { - auto& eglManager = renderState.getRenderThread().eglManager(); - display = eglManager.eglDisplay(); - err = eglManager.createReleaseFence(st.mUseFenceSync, &mImageSlots[slot].eglFence(), - releaseFence); - } else { - err = renderState.getRenderThread().vulkanManager().createReleaseFence( - releaseFence, renderState.getRenderThread().getGrContext()); - } - if (OK != err) { - st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY, - EGL_NO_SYNC_KHR); - return nullptr; - } - - if (releaseFence.get()) { - status_t err = st.addReleaseFenceLocked( - st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, releaseFence); - if (err != OK) { - IMG_LOGE("dequeueImage: error adding release fence: %s (%d)", strerror(-err), err); - st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY, - EGL_NO_SYNC_KHR); - return nullptr; - } - } - - // Finally release the old buffer. - status_t status = st.releaseBufferLocked( - st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, display, - mImageSlots[st.mCurrentTexture].eglFence()); - if (status < NO_ERROR) { - IMG_LOGE("dequeueImage: failed to release buffer: %s (%d)", strerror(-status), status); - err = status; - // Keep going, with error raised. - } - } - - // Update the state. - st.mCurrentTexture = slot; - st.mCurrentCrop = item.mCrop; - st.mCurrentTransform = item.mTransform; - st.mCurrentScalingMode = item.mScalingMode; - st.mCurrentTimestamp = item.mTimestamp; - st.mCurrentDataSpace = item.mDataSpace; - st.mCurrentFence = item.mFence; - st.mCurrentFenceTime = item.mFenceTime; - st.mCurrentFrameNumber = item.mFrameNumber; - st.computeCurrentTransformMatrixLocked(); - - *queueEmpty = false; - mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace, true, - renderState.getRenderThread().getGrContext()); - return mImageSlots[slot].getImage(); -} - -} /* namespace android */ diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h deleted file mode 100644 index 3e2a91a251f7..000000000000 --- a/libs/hwui/surfacetexture/ImageConsumer.h +++ /dev/null @@ -1,115 +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. - */ - -#pragma once - -#include -#include - -#include - -#include -#include -#include -#include - -namespace android { - -namespace uirenderer { -class RenderState; -} - -class AutoBackendTextureRelease; -class SurfaceTexture; - -/* - * ImageConsumer implements the parts of SurfaceTexture that deal with - * images consumed by HWUI view system. - */ -class ImageConsumer { -public: - sk_sp dequeueImage(bool* queueEmpty, SurfaceTexture& cb, - uirenderer::RenderState& renderState); - - /** - * onAcquireBufferLocked amends the ConsumerBase method to update the - * mImageSlots array in addition to the ConsumerBase behavior. - */ - void onAcquireBufferLocked(BufferItem* item); - - /** - * onReleaseBufferLocked amends the ConsumerBase method to update the - * mImageSlots array in addition to the ConsumerBase. - */ - void onReleaseBufferLocked(int slot); - - /** - * onFreeBufferLocked frees up the given buffer slot. If the slot has been - * initialized this will release the reference to the GraphicBuffer in that - * slot and destroy the SkImage in that slot. Otherwise it has no effect. - */ - void onFreeBufferLocked(int slotIndex); - -private: - /** - * ImageSlot contains the information and object references that - * ImageConsumer maintains about a BufferQueue buffer slot. - */ - class ImageSlot { - public: - ImageSlot() : mDataspace(HAL_DATASPACE_UNKNOWN), mEglFence(EGL_NO_SYNC_KHR) {} - - ~ImageSlot() { clear(); } - - void createIfNeeded(sp graphicBuffer, android_dataspace dataspace, - bool forceCreate, GrContext* context); - - void clear(); - - inline EGLSyncKHR& eglFence() { return mEglFence; } - - sk_sp getImage(); - - private: - // the dataspace associated with the current image - android_dataspace mDataspace; - - /** - * mEglFence is the EGL sync object that must signal before the buffer - * associated with this buffer slot may be dequeued. - */ - EGLSyncKHR mEglFence; - - /** - * mTextureRelease may outlive ImageConsumer, if the last ref is held by an SkImage. - * ImageConsumer holds one ref to mTextureRelease, which is decremented by "clear". - */ - AutoBackendTextureRelease* mTextureRelease = nullptr; - }; - - /** - * ImageConsumer stores the SkImages that have been allocated by the BufferQueue - * for each buffer slot. It is initialized to null pointers, and gets - * filled in with the result of BufferQueue::acquire when the - * client dequeues a buffer from a - * slot that has not yet been used. The buffer allocated to a slot will also - * be replaced if the requested buffer usage or geometry differs from that - * of the buffer allocated to a slot. - */ - ImageSlot mImageSlots[BufferQueueDefs::NUM_BUFFER_SLOTS]; -}; - -} /* namespace android */ diff --git a/libs/hwui/surfacetexture/SurfaceTexture.cpp b/libs/hwui/surfacetexture/SurfaceTexture.cpp deleted file mode 100644 index a27db6591d6a..000000000000 --- a/libs/hwui/surfacetexture/SurfaceTexture.cpp +++ /dev/null @@ -1,499 +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. - */ - -#include -#include -#include -#include - -#include - -#include "Matrix.h" -#include "SurfaceTexture.h" -#include "ImageConsumer.h" - -namespace android { - -// Macros for including the SurfaceTexture name in log messages -#define SFT_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -#define SFT_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -#define SFT_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define SFT_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) - -static const mat4 mtxIdentity; - -SurfaceTexture::SurfaceTexture(const sp& bq, uint32_t tex, - uint32_t texTarget, bool useFenceSync, bool isControlledByApp) - : ConsumerBase(bq, isControlledByApp) - , mCurrentCrop(Rect::EMPTY_RECT) - , mCurrentTransform(0) - , mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE) - , mCurrentFence(Fence::NO_FENCE) - , mCurrentTimestamp(0) - , mCurrentDataSpace(HAL_DATASPACE_UNKNOWN) - , mCurrentFrameNumber(0) - , mDefaultWidth(1) - , mDefaultHeight(1) - , mFilteringEnabled(true) - , mTexName(tex) - , mUseFenceSync(useFenceSync) - , mTexTarget(texTarget) - , mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) - , mOpMode(OpMode::attachedToGL) { - SFT_LOGV("SurfaceTexture"); - - memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); - - mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); -} - -SurfaceTexture::SurfaceTexture(const sp& bq, uint32_t texTarget, - bool useFenceSync, bool isControlledByApp) - : ConsumerBase(bq, isControlledByApp) - , mCurrentCrop(Rect::EMPTY_RECT) - , mCurrentTransform(0) - , mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE) - , mCurrentFence(Fence::NO_FENCE) - , mCurrentTimestamp(0) - , mCurrentDataSpace(HAL_DATASPACE_UNKNOWN) - , mCurrentFrameNumber(0) - , mDefaultWidth(1) - , mDefaultHeight(1) - , mFilteringEnabled(true) - , mTexName(0) - , mUseFenceSync(useFenceSync) - , mTexTarget(texTarget) - , mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) - , mOpMode(OpMode::detached) { - SFT_LOGV("SurfaceTexture"); - - memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); - - mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); -} - -status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - SFT_LOGE("setDefaultBufferSize: SurfaceTexture is abandoned!"); - return NO_INIT; - } - mDefaultWidth = w; - mDefaultHeight = h; - return mConsumer->setDefaultBufferSize(w, h); -} - -status_t SurfaceTexture::updateTexImage() { - ATRACE_CALL(); - SFT_LOGV("updateTexImage"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - SFT_LOGE("updateTexImage: SurfaceTexture is abandoned!"); - return NO_INIT; - } - - return mEGLConsumer.updateTexImage(*this); -} - -status_t SurfaceTexture::releaseTexImage() { - // releaseTexImage can be invoked even when not attached to a GL context. - ATRACE_CALL(); - SFT_LOGV("releaseTexImage"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - SFT_LOGE("releaseTexImage: SurfaceTexture is abandoned!"); - return NO_INIT; - } - - return mEGLConsumer.releaseTexImage(*this); -} - -status_t SurfaceTexture::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, - uint64_t maxFrameNumber) { - status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber); - if (err != NO_ERROR) { - return err; - } - - switch (mOpMode) { - case OpMode::attachedToView: - mImageConsumer.onAcquireBufferLocked(item); - break; - case OpMode::attachedToGL: - mEGLConsumer.onAcquireBufferLocked(item, *this); - break; - case OpMode::detached: - break; - } - - return NO_ERROR; -} - -status_t SurfaceTexture::releaseBufferLocked(int buf, sp graphicBuffer, - EGLDisplay display, EGLSyncKHR eglFence) { - // release the buffer if it hasn't already been discarded by the - // BufferQueue. This can happen, for example, when the producer of this - // buffer has reallocated the original buffer slot after this buffer - // was acquired. - status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer, display, eglFence); - // We could be releasing an EGL/Vulkan buffer, even if not currently attached to a GL context. - mImageConsumer.onReleaseBufferLocked(buf); - mEGLConsumer.onReleaseBufferLocked(buf); - return err; -} - -status_t SurfaceTexture::detachFromContext() { - ATRACE_CALL(); - SFT_LOGV("detachFromContext"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - SFT_LOGE("detachFromContext: abandoned SurfaceTexture"); - return NO_INIT; - } - - if (mOpMode != OpMode::attachedToGL) { - SFT_LOGE("detachFromContext: SurfaceTexture is not attached to a GL context"); - return INVALID_OPERATION; - } - - status_t err = mEGLConsumer.detachFromContext(*this); - if (err == OK) { - mOpMode = OpMode::detached; - } - - return err; -} - -status_t SurfaceTexture::attachToContext(uint32_t tex) { - ATRACE_CALL(); - SFT_LOGV("attachToContext"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - SFT_LOGE("attachToContext: abandoned SurfaceTexture"); - return NO_INIT; - } - - if (mOpMode != OpMode::detached) { - SFT_LOGE( - "attachToContext: SurfaceTexture is already attached to a " - "context"); - return INVALID_OPERATION; - } - - if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - // release possible ImageConsumer cache - mImageConsumer.onFreeBufferLocked(mCurrentTexture); - } - - return mEGLConsumer.attachToContext(tex, *this); -} - -void SurfaceTexture::attachToView() { - ATRACE_CALL(); - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - SFT_LOGE("attachToView: abandoned SurfaceTexture"); - return; - } - if (mOpMode == OpMode::detached) { - mOpMode = OpMode::attachedToView; - - if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - // release possible EGLConsumer texture cache - mEGLConsumer.onFreeBufferLocked(mCurrentTexture); - mEGLConsumer.onAbandonLocked(); - } - } else { - SFT_LOGE("attachToView: already attached"); - } -} - -void SurfaceTexture::detachFromView() { - ATRACE_CALL(); - Mutex::Autolock _l(mMutex); - - if (mAbandoned) { - SFT_LOGE("detachFromView: abandoned SurfaceTexture"); - return; - } - - if (mOpMode == OpMode::attachedToView) { - mOpMode = OpMode::detached; - // Free all EglImage and VkImage before the context is destroyed. - for (int i=0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) { - mImageConsumer.onFreeBufferLocked(i); - } - } else { - SFT_LOGE("detachFromView: not attached to View"); - } -} - -uint32_t SurfaceTexture::getCurrentTextureTarget() const { - return mTexTarget; -} - -void SurfaceTexture::getTransformMatrix(float mtx[16]) { - Mutex::Autolock lock(mMutex); - memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); -} - -void SurfaceTexture::setFilteringEnabled(bool enabled) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - SFT_LOGE("setFilteringEnabled: SurfaceTexture is abandoned!"); - return; - } - bool needsRecompute = mFilteringEnabled != enabled; - mFilteringEnabled = enabled; - - if (needsRecompute && mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) { - SFT_LOGD("setFilteringEnabled called with no current item"); - } - - if (needsRecompute && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - computeCurrentTransformMatrixLocked(); - } -} - -void SurfaceTexture::computeCurrentTransformMatrixLocked() { - SFT_LOGV("computeCurrentTransformMatrixLocked"); - sp buf = (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) - ? nullptr - : mSlots[mCurrentTexture].mGraphicBuffer; - if (buf == nullptr) { - SFT_LOGD("computeCurrentTransformMatrixLocked: no current item"); - } - computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop, mCurrentTransform, - mFilteringEnabled); -} - -void SurfaceTexture::computeTransformMatrix(float outTransform[16], const sp& buf, - const Rect& cropRect, uint32_t transform, - bool filtering) { - // Transform matrices - static const mat4 mtxFlipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); - static const mat4 mtxFlipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); - static const mat4 mtxRot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); - - mat4 xform; - if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { - xform *= mtxFlipH; - } - if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { - xform *= mtxFlipV; - } - if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - xform *= mtxRot90; - } - - if (!cropRect.isEmpty() && buf.get()) { - float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; - float bufferWidth = buf->getWidth(); - float bufferHeight = buf->getHeight(); - float shrinkAmount = 0.0f; - if (filtering) { - // In order to prevent bilinear sampling beyond the edge of the - // crop rectangle we may need to shrink it by 2 texels in each - // dimension. Normally this would just need to take 1/2 a texel - // off each end, but because the chroma channels of YUV420 images - // are subsampled we may need to shrink the crop region by a whole - // texel on each side. - switch (buf->getPixelFormat()) { - case PIXEL_FORMAT_RGBA_8888: - case PIXEL_FORMAT_RGBX_8888: - case PIXEL_FORMAT_RGBA_FP16: - case PIXEL_FORMAT_RGBA_1010102: - case PIXEL_FORMAT_RGB_888: - case PIXEL_FORMAT_RGB_565: - case PIXEL_FORMAT_BGRA_8888: - // We know there's no subsampling of any channels, so we - // only need to shrink by a half a pixel. - shrinkAmount = 0.5; - break; - - default: - // If we don't recognize the format, we must assume the - // worst case (that we care about), which is YUV420. - shrinkAmount = 1.0; - break; - } - } - - // Only shrink the dimensions that are not the size of the buffer. - if (cropRect.width() < bufferWidth) { - tx = (float(cropRect.left) + shrinkAmount) / bufferWidth; - sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth; - } - if (cropRect.height() < bufferHeight) { - ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight; - sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight; - } - - mat4 crop(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1); - xform = crop * xform; - } - - // SurfaceFlinger expects the top of its window textures to be at a Y - // coordinate of 0, so SurfaceTexture must behave the same way. We don't - // want to expose this to applications, however, so we must add an - // additional vertical flip to the transform after all the other transforms. - xform = mtxFlipV * xform; - - memcpy(outTransform, xform.asArray(), sizeof(xform)); -} - -Rect SurfaceTexture::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) { - Rect outCrop = crop; - - uint32_t newWidth = static_cast(crop.width()); - uint32_t newHeight = static_cast(crop.height()); - - if (newWidth * bufferHeight > newHeight * bufferWidth) { - newWidth = newHeight * bufferWidth / bufferHeight; - ALOGV("too wide: newWidth = %d", newWidth); - } else if (newWidth * bufferHeight < newHeight * bufferWidth) { - newHeight = newWidth * bufferHeight / bufferWidth; - ALOGV("too tall: newHeight = %d", newHeight); - } - - uint32_t currentWidth = static_cast(crop.width()); - uint32_t currentHeight = static_cast(crop.height()); - - // The crop is too wide - if (newWidth < currentWidth) { - uint32_t dw = currentWidth - newWidth; - auto halfdw = dw / 2; - outCrop.left += halfdw; - // Not halfdw because it would subtract 1 too few when dw is odd - outCrop.right -= (dw - halfdw); - // The crop is too tall - } else if (newHeight < currentHeight) { - uint32_t dh = currentHeight - newHeight; - auto halfdh = dh / 2; - outCrop.top += halfdh; - // Not halfdh because it would subtract 1 too few when dh is odd - outCrop.bottom -= (dh - halfdh); - } - - ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right, - outCrop.bottom); - - return outCrop; -} - -nsecs_t SurfaceTexture::getTimestamp() { - SFT_LOGV("getTimestamp"); - Mutex::Autolock lock(mMutex); - return mCurrentTimestamp; -} - -android_dataspace SurfaceTexture::getCurrentDataSpace() { - SFT_LOGV("getCurrentDataSpace"); - Mutex::Autolock lock(mMutex); - return mCurrentDataSpace; -} - -uint64_t SurfaceTexture::getFrameNumber() { - SFT_LOGV("getFrameNumber"); - Mutex::Autolock lock(mMutex); - return mCurrentFrameNumber; -} - -Rect SurfaceTexture::getCurrentCrop() const { - Mutex::Autolock lock(mMutex); - return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) - ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight) - : mCurrentCrop; -} - -uint32_t SurfaceTexture::getCurrentTransform() const { - Mutex::Autolock lock(mMutex); - return mCurrentTransform; -} - -uint32_t SurfaceTexture::getCurrentScalingMode() const { - Mutex::Autolock lock(mMutex); - return mCurrentScalingMode; -} - -sp SurfaceTexture::getCurrentFence() const { - Mutex::Autolock lock(mMutex); - return mCurrentFence; -} - -std::shared_ptr SurfaceTexture::getCurrentFenceTime() const { - Mutex::Autolock lock(mMutex); - return mCurrentFenceTime; -} - -void SurfaceTexture::freeBufferLocked(int slotIndex) { - SFT_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); - if (slotIndex == mCurrentTexture) { - mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; - } - // The slotIndex buffer could have EGL or SkImage cache, but there is no way to tell for sure. - // Buffers can be freed after SurfaceTexture has detached from GL context or View. - mImageConsumer.onFreeBufferLocked(slotIndex); - mEGLConsumer.onFreeBufferLocked(slotIndex); - ConsumerBase::freeBufferLocked(slotIndex); -} - -void SurfaceTexture::abandonLocked() { - SFT_LOGV("abandonLocked"); - mEGLConsumer.onAbandonLocked(); - ConsumerBase::abandonLocked(); -} - -status_t SurfaceTexture::setConsumerUsageBits(uint64_t usage) { - return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS); -} - -void SurfaceTexture::dumpLocked(String8& result, const char* prefix) const { - result.appendFormat( - "%smTexName=%d mCurrentTexture=%d\n" - "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n", - prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, mCurrentCrop.top, - mCurrentCrop.right, mCurrentCrop.bottom, mCurrentTransform); - - ConsumerBase::dumpLocked(result, prefix); -} - -sk_sp SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, bool* queueEmpty, - uirenderer::RenderState& renderState) { - Mutex::Autolock _l(mMutex); - - if (mAbandoned) { - SFT_LOGE("dequeueImage: SurfaceTexture is abandoned!"); - return nullptr; - } - - if (mOpMode != OpMode::attachedToView) { - SFT_LOGE("dequeueImage: SurfaceTexture is not attached to a View"); - return nullptr; - } - - auto image = mImageConsumer.dequeueImage(queueEmpty, *this, renderState); - if (image.get()) { - uirenderer::mat4(mCurrentTransformMatrix).copyTo(transformMatrix); - } - return image; -} - -} // namespace android diff --git a/libs/hwui/surfacetexture/SurfaceTexture.h b/libs/hwui/surfacetexture/SurfaceTexture.h deleted file mode 100644 index b5d136ff3058..000000000000 --- a/libs/hwui/surfacetexture/SurfaceTexture.h +++ /dev/null @@ -1,452 +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. - */ - -#pragma once - -#include -#include - -#include -#include - -#include -#include - -#include "EGLConsumer.h" -#include "ImageConsumer.h" - -namespace android { - -namespace uirenderer { -class RenderState; -} - -/* - * SurfaceTexture consumes buffers of graphics data from a BufferQueue, - * and makes them available to HWUI render thread as a SkImage and to - * an application GL render thread as an OpenGL texture. - * - * When attached to an application GL render thread, a typical usage - * pattern is to set up the SurfaceTexture with the - * desired options, and call updateTexImage() when a new frame is desired. - * If a new frame is available, the texture will be updated. If not, - * the previous contents are retained. - * - * When attached to a HWUI render thread, the TextureView implementation - * calls dequeueImage, which either pulls a new SkImage or returns the - * last cached SkImage if BufferQueue is empty. - * When attached to HWUI render thread, SurfaceTexture is compatible to - * both Vulkan and GL drawing pipelines. - */ -class ANDROID_API SurfaceTexture : public ConsumerBase { -public: - enum { TEXTURE_EXTERNAL = 0x8D65 }; // GL_TEXTURE_EXTERNAL_OES - typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; - - /** - * SurfaceTexture constructs a new SurfaceTexture object. If the constructor with - * the tex parameter is used, tex indicates the name of the OpenGL ES - * texture to which images are to be streamed. texTarget specifies the - * OpenGL ES texture target to which the texture will be bound in - * updateTexImage. useFenceSync specifies whether fences should be used to - * synchronize access to buffers if that behavior is enabled at - * compile-time. - * - * A SurfaceTexture may be detached from one OpenGL ES context and then - * attached to a different context using the detachFromContext and - * attachToContext methods, respectively. The intention of these methods is - * purely to allow a SurfaceTexture to be transferred from one consumer - * context to another. If such a transfer is not needed there is no - * requirement that either of these methods be called. - * - * If the constructor with the tex parameter is used, the SurfaceTexture is - * created in a state where it is considered attached to an OpenGL ES - * context for the purposes of the attachToContext and detachFromContext - * methods. However, despite being considered "attached" to a context, the - * specific OpenGL ES context doesn't get latched until the first call to - * updateTexImage. After that point, all calls to updateTexImage must be - * made with the same OpenGL ES context current. - * - * If the constructor without the tex parameter is used, the SurfaceTexture is - * created in a detached state, and attachToContext must be called before - * calls to updateTexImage. - */ - SurfaceTexture(const sp& bq, uint32_t tex, uint32_t texureTarget, - bool useFenceSync, bool isControlledByApp); - - SurfaceTexture(const sp& bq, uint32_t texureTarget, bool useFenceSync, - bool isControlledByApp); - - /** - * updateTexImage acquires the most recently queued buffer, and sets the - * image contents of the target texture to it. - * - * This call may only be made while the OpenGL ES context to which the - * target texture belongs is bound to the calling thread. - * - * This calls doGLFenceWait to ensure proper synchronization. - */ - status_t updateTexImage(); - - /** - * releaseTexImage releases the texture acquired in updateTexImage(). - * This is intended to be used in single buffer mode. - * - * This call may only be made while the OpenGL ES context to which the - * target texture belongs is bound to the calling thread. - */ - status_t releaseTexImage(); - - /** - * getTransformMatrix retrieves the 4x4 texture coordinate transform matrix - * associated with the texture image set by the most recent call to - * updateTexImage. - * - * This transform matrix maps 2D homogeneous texture coordinates of the form - * (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the texture - * coordinate that should be used to sample that location from the texture. - * Sampling the texture outside of the range of this transform is undefined. - * - * This transform is necessary to compensate for transforms that the stream - * content producer may implicitly apply to the content. By forcing users of - * a SurfaceTexture to apply this transform we avoid performing an extra - * copy of the data that would be needed to hide the transform from the - * user. - * - * The matrix is stored in column-major order so that it may be passed - * directly to OpenGL ES via the glLoadMatrixf or glUniformMatrix4fv - * functions. - */ - void getTransformMatrix(float mtx[16]); - - /** - * Computes the transform matrix documented by getTransformMatrix - * from the BufferItem sub parts. - */ - static void computeTransformMatrix(float outTransform[16], const sp& buf, - const Rect& cropRect, uint32_t transform, bool filtering); - - /** - * Scale the crop down horizontally or vertically such that it has the - * same aspect ratio as the buffer does. - */ - static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight); - - /** - * getTimestamp retrieves the timestamp associated with the texture image - * set by the most recent call to updateTexImage. - * - * The timestamp is in nanoseconds, and is monotonically increasing. Its - * other semantics (zero point, etc) are source-dependent and should be - * documented by the source. - */ - int64_t getTimestamp(); - - /** - * getDataSpace retrieves the DataSpace associated with the texture image - * set by the most recent call to updateTexImage. - */ - android_dataspace getCurrentDataSpace(); - - /** - * getFrameNumber retrieves the frame number associated with the texture - * image set by the most recent call to updateTexImage. - * - * The frame number is an incrementing counter set to 0 at the creation of - * the BufferQueue associated with this consumer. - */ - uint64_t getFrameNumber(); - - /** - * setDefaultBufferSize is used to set the size of buffers returned by - * requestBuffers when a with and height of zero is requested. - * A call to setDefaultBufferSize() may trigger requestBuffers() to - * be called from the client. - * The width and height parameters must be no greater than the minimum of - * GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). - * An error due to invalid dimensions might not be reported until - * updateTexImage() is called. - */ - status_t setDefaultBufferSize(uint32_t width, uint32_t height); - - /** - * setFilteringEnabled sets whether the transform matrix should be computed - * for use with bilinear filtering. - */ - void setFilteringEnabled(bool enabled); - - /** - * getCurrentTextureTarget returns the texture target of the current - * texture as returned by updateTexImage(). - */ - uint32_t getCurrentTextureTarget() const; - - /** - * getCurrentCrop returns the cropping rectangle of the current buffer. - */ - Rect getCurrentCrop() const; - - /** - * getCurrentTransform returns the transform of the current buffer. - */ - uint32_t getCurrentTransform() const; - - /** - * getCurrentScalingMode returns the scaling mode of the current buffer. - */ - uint32_t getCurrentScalingMode() const; - - /** - * getCurrentFence returns the fence indicating when the current buffer is - * ready to be read from. - */ - sp getCurrentFence() const; - - /** - * getCurrentFence returns the FenceTime indicating when the current - * buffer is ready to be read from. - */ - std::shared_ptr getCurrentFenceTime() const; - - /** - * setConsumerUsageBits overrides the ConsumerBase method to OR - * DEFAULT_USAGE_FLAGS to usage. - */ - status_t setConsumerUsageBits(uint64_t usage); - - /** - * detachFromContext detaches the SurfaceTexture from the calling thread's - * current OpenGL ES context. This context must be the same as the context - * that was current for previous calls to updateTexImage. - * - * Detaching a SurfaceTexture from an OpenGL ES context will result in the - * deletion of the OpenGL ES texture object into which the images were being - * streamed. After a SurfaceTexture has been detached from the OpenGL ES - * context calls to updateTexImage will fail returning INVALID_OPERATION - * until the SurfaceTexture is attached to a new OpenGL ES context using the - * attachToContext method. - */ - status_t detachFromContext(); - - /** - * attachToContext attaches a SurfaceTexture that is currently in the - * 'detached' state to the current OpenGL ES context. A SurfaceTexture is - * in the 'detached' state iff detachFromContext has successfully been - * called and no calls to attachToContext have succeeded since the last - * detachFromContext call. Calls to attachToContext made on a - * SurfaceTexture that is not in the 'detached' state will result in an - * INVALID_OPERATION error. - * - * The tex argument specifies the OpenGL ES texture object name in the - * new context into which the image contents will be streamed. A successful - * call to attachToContext will result in this texture object being bound to - * the texture target and populated with the image contents that were - * current at the time of the last call to detachFromContext. - */ - status_t attachToContext(uint32_t tex); - - sk_sp dequeueImage(SkMatrix& transformMatrix, bool* queueEmpty, - uirenderer::RenderState& renderState); - - /** - * attachToView attaches a SurfaceTexture that is currently in the - * 'detached' state to HWUI View system. - */ - void attachToView(); - - /** - * detachFromView detaches a SurfaceTexture from HWUI View system. - */ - void detachFromView(); - -protected: - /** - * abandonLocked overrides the ConsumerBase method to clear - * mCurrentTextureImage in addition to the ConsumerBase behavior. - */ - virtual void abandonLocked(); - - /** - * dumpLocked overrides the ConsumerBase method to dump SurfaceTexture- - * specific info in addition to the ConsumerBase behavior. - */ - virtual void dumpLocked(String8& result, const char* prefix) const override; - - /** - * acquireBufferLocked overrides the ConsumerBase method to update the - * mEglSlots array in addition to the ConsumerBase behavior. - */ - virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, - uint64_t maxFrameNumber = 0) override; - - /** - * releaseBufferLocked overrides the ConsumerBase method to update the - * mEglSlots array in addition to the ConsumerBase. - */ - virtual status_t releaseBufferLocked(int slot, const sp graphicBuffer, - EGLDisplay display, EGLSyncKHR eglFence) override; - - /** - * freeBufferLocked frees up the given buffer slot. If the slot has been - * initialized this will release the reference to the GraphicBuffer in that - * slot and destroy the EGLImage in that slot. Otherwise it has no effect. - * - * This method must be called with mMutex locked. - */ - virtual void freeBufferLocked(int slotIndex); - - /** - * computeCurrentTransformMatrixLocked computes the transform matrix for the - * current texture. It uses mCurrentTransform and the current GraphicBuffer - * to compute this matrix and stores it in mCurrentTransformMatrix. - * mCurrentTextureImage must not be NULL. - */ - void computeCurrentTransformMatrixLocked(); - - /** - * The default consumer usage flags that SurfaceTexture always sets on its - * BufferQueue instance; these will be OR:d with any additional flags passed - * from the SurfaceTexture user. In particular, SurfaceTexture will always - * consume buffers as hardware textures. - */ - static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; - - /** - * mCurrentCrop is the crop rectangle that applies to the current texture. - * It gets set each time updateTexImage is called. - */ - Rect mCurrentCrop; - - /** - * mCurrentTransform is the transform identifier for the current texture. It - * gets set each time updateTexImage is called. - */ - uint32_t mCurrentTransform; - - /** - * mCurrentScalingMode is the scaling mode for the current texture. It gets - * set each time updateTexImage is called. - */ - uint32_t mCurrentScalingMode; - - /** - * mCurrentFence is the fence received from BufferQueue in updateTexImage. - */ - sp mCurrentFence; - - /** - * The FenceTime wrapper around mCurrentFence. - */ - std::shared_ptr mCurrentFenceTime{FenceTime::NO_FENCE}; - - /** - * mCurrentTransformMatrix is the transform matrix for the current texture. - * It gets computed by computeTransformMatrix each time updateTexImage is - * called. - */ - float mCurrentTransformMatrix[16]; - - /** - * mCurrentTimestamp is the timestamp for the current texture. It - * gets set each time updateTexImage is called. - */ - int64_t mCurrentTimestamp; - - /** - * mCurrentDataSpace is the dataspace for the current texture. It - * gets set each time updateTexImage is called. - */ - android_dataspace mCurrentDataSpace; - - /** - * mCurrentFrameNumber is the frame counter for the current texture. - * It gets set each time updateTexImage is called. - */ - uint64_t mCurrentFrameNumber; - - uint32_t mDefaultWidth, mDefaultHeight; - - /** - * mFilteringEnabled indicates whether the transform matrix is computed for - * use with bilinear filtering. It defaults to true and is changed by - * setFilteringEnabled(). - */ - bool mFilteringEnabled; - - /** - * mTexName is the name of the OpenGL texture to which streamed images will - * be bound when updateTexImage is called. It is set at construction time - * and can be changed with a call to attachToContext. - */ - uint32_t mTexName; - - /** - * mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync - * extension should be used to prevent buffers from being dequeued before - * it's safe for them to be written. It gets set at construction time and - * never changes. - */ - const bool mUseFenceSync; - - /** - * mTexTarget is the GL texture target with which the GL texture object is - * associated. It is set in the constructor and never changed. It is - * almost always GL_TEXTURE_EXTERNAL_OES except for one use case in Android - * Browser. In that case it is set to GL_TEXTURE_2D to allow - * glCopyTexSubImage to read from the texture. This is a hack to work - * around a GL driver limitation on the number of FBO attachments, which the - * browser's tile cache exceeds. - */ - const uint32_t mTexTarget; - - /** - * mCurrentTexture is the buffer slot index of the buffer that is currently - * bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT, - * indicating that no buffer slot is currently bound to the texture. Note, - * however, that a value of INVALID_BUFFER_SLOT does not necessarily mean - * that no buffer is bound to the texture. A call to setBufferCount will - * reset mCurrentTexture to INVALID_BUFFER_SLOT. - */ - int mCurrentTexture; - - enum class OpMode { detached, attachedToView, attachedToGL }; - /** - * mOpMode indicates whether the SurfaceTexture is currently attached to - * an OpenGL ES context or the HWUI view system. For legacy reasons, this is initialized to, - * "attachedToGL" indicating that the SurfaceTexture is considered to be attached to - * whatever GL context is current at the time of the first updateTexImage call. - * It is set to "detached" by detachFromContext, and then set to "attachedToGL" again by - * attachToContext. - * attachToView/detachFromView are used to attach/detach from HWUI view system. - */ - OpMode mOpMode; - - /** - * mEGLConsumer has SurfaceTexture logic used when attached to GL context. - */ - EGLConsumer mEGLConsumer; - - /** - * mImageConsumer has SurfaceTexture logic used when attached to HWUI view system. - */ - ImageConsumer mImageConsumer; - - friend class ImageConsumer; - friend class EGLConsumer; -}; - -// ---------------------------------------------------------------------------- -} // namespace android diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index e7124df72beb..91a808df3657 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -29,6 +29,7 @@ #include #include +#include namespace android { namespace uirenderer { diff --git a/native/android/surface_texture.cpp b/native/android/surface_texture.cpp index ced2792775d4..3049ec16e2d4 100644 --- a/native/android/surface_texture.cpp +++ b/native/android/surface_texture.cpp @@ -23,25 +23,19 @@ #include -#include +#include -#include "surfacetexture/SurfaceTexture.h" +#include using namespace android; -struct ASurfaceTexture { - sp consumer; - sp producer; -}; - ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) { if (!surfacetexture || !android_SurfaceTexture_isInstanceOf(env, surfacetexture)) { return nullptr; } - ASurfaceTexture* ast = new ASurfaceTexture; - ast->consumer = SurfaceTexture_getSurfaceTexture(env, surfacetexture); - ast->producer = SurfaceTexture_getProducer(env, surfacetexture); - return ast; + auto consumer = SurfaceTexture_getSurfaceTexture(env, surfacetexture); + auto producer = SurfaceTexture_getProducer(env, surfacetexture); + return ASurfaceTexture_create(consumer, producer); } ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) { -- cgit v1.2.3-59-g8ed1b From 440c5ac251c4ed9b3f27daa8db8d738087530dbe Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 22 Oct 2019 10:30:31 -0700 Subject: [AChoreographer] Consolidate AChoreographer source files Now that AChroeographer is defined in libnativedisplay, libandroid should not need its own copy. Instead what we do is: * Statically link libnativedisplay into libandroid * Delete choreographer.cpp This structure is the same as that of ANativeWindow. Bug: 136262896 Test: builds Change-Id: I159d69398bb33ccd7b01aae798d14c04438355c1 --- native/android/Android.bp | 5 +- native/android/choreographer.cpp | 225 --------------------------------------- 2 files changed, 2 insertions(+), 228 deletions(-) delete mode 100644 native/android/choreographer.cpp (limited to 'native/android') diff --git a/native/android/Android.bp b/native/android/Android.bp index 91297b0de02e..9d93c9b7b605 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -36,7 +36,6 @@ cc_library_shared { srcs: [ "asset_manager.cpp", - "choreographer.cpp", "configuration.cpp", "hardware_buffer_jni.cpp", "input.cpp", @@ -80,7 +79,7 @@ cc_library_shared { "libarect", ], - whole_static_libs: ["libnativewindow"], + whole_static_libs: ["libnativedisplay", "libnativewindow"], export_static_lib_headers: ["libarect"], @@ -142,4 +141,4 @@ filegroup { "aidl/com/android/internal/compat/IPlatformCompatNative.aidl", ], path: "aidl", -} \ No newline at end of file +} diff --git a/native/android/choreographer.cpp b/native/android/choreographer.cpp deleted file mode 100644 index 63e073405fe0..000000000000 --- a/native/android/choreographer.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2015 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 "Choreographer" -//#define LOG_NDEBUG 0 - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace android { - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -struct FrameCallback { - AChoreographer_frameCallback callback; - AChoreographer_frameCallback64 callback64; - void* data; - nsecs_t dueTime; - - inline bool operator<(const FrameCallback& rhs) const { - // Note that this is intentionally flipped because we want callbacks due sooner to be at - // the head of the queue - return dueTime > rhs.dueTime; - } -}; - - -class Choreographer : public DisplayEventDispatcher, public MessageHandler { -public: - void postFrameCallbackDelayed(AChoreographer_frameCallback cb, - AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay); - - enum { - MSG_SCHEDULE_CALLBACKS = 0, - MSG_SCHEDULE_VSYNC = 1 - }; - virtual void handleMessage(const Message& message) override; - - static Choreographer* getForThread(); - -protected: - virtual ~Choreographer() = default; - -private: - explicit Choreographer(const sp& looper); - Choreographer(const Choreographer&) = delete; - - void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override; - void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override; - void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, - int32_t configId) override; - - void scheduleCallbacks(); - - // Protected by mLock - std::priority_queue mCallbacks; - - mutable Mutex mLock; - - const sp mLooper; - const std::thread::id mThreadId; -}; - - -static thread_local Choreographer* gChoreographer; -Choreographer* Choreographer::getForThread() { - if (gChoreographer == nullptr) { - sp looper = Looper::getForThread(); - if (!looper.get()) { - ALOGW("No looper prepared for thread"); - return nullptr; - } - gChoreographer = new Choreographer(looper); - status_t result = gChoreographer->initialize(); - if (result != OK) { - ALOGW("Failed to initialize"); - return nullptr; - } - } - return gChoreographer; -} - -Choreographer::Choreographer(const sp& looper) : - DisplayEventDispatcher(looper), mLooper(looper), mThreadId(std::this_thread::get_id()) { -} - -void Choreographer::postFrameCallbackDelayed( - AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - FrameCallback callback{cb, cb64, data, now + delay}; - { - AutoMutex _l{mLock}; - mCallbacks.push(callback); - } - if (callback.dueTime <= now) { - if (std::this_thread::get_id() != mThreadId) { - Message m{MSG_SCHEDULE_VSYNC}; - mLooper->sendMessage(this, m); - } else { - scheduleVsync(); - } - } else { - Message m{MSG_SCHEDULE_CALLBACKS}; - mLooper->sendMessageDelayed(delay, this, m); - } -} - -void Choreographer::scheduleCallbacks() { - AutoMutex _{mLock}; - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - if (mCallbacks.top().dueTime <= now) { - ALOGV("choreographer %p ~ scheduling vsync", this); - scheduleVsync(); - return; - } -} - -// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the -// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for -// the internal display implicitly. -void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) { - std::vector callbacks{}; - { - AutoMutex _l{mLock}; - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - while (!mCallbacks.empty() && mCallbacks.top().dueTime < now) { - callbacks.push_back(mCallbacks.top()); - mCallbacks.pop(); - } - } - for (const auto& cb : callbacks) { - if (cb.callback64 != nullptr) { - cb.callback64(timestamp, cb.data); - } else if (cb.callback != nullptr) { - cb.callback(timestamp, cb.data); - } - } -} - -void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) { - ALOGV("choreographer %p ~ received hotplug event (displayId=%" - ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", connected=%s), ignoring.", - this, displayId, toString(connected)); -} - -void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId, - int32_t configId) { - ALOGV("choreographer %p ~ received config changed event (displayId=%" - ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%s), ignoring.", - this, displayId, toString(configId)); -} - -void Choreographer::handleMessage(const Message& message) { - switch (message.what) { - case MSG_SCHEDULE_CALLBACKS: - scheduleCallbacks(); - break; - case MSG_SCHEDULE_VSYNC: - scheduleVsync(); - break; - } -} - -} - -/* Glue for the NDK interface */ - -using android::Choreographer; - -static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) { - return reinterpret_cast(choreographer); -} - -static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) { - return reinterpret_cast(choreographer); -} - -AChoreographer* AChoreographer_getInstance() { - return Choreographer_to_AChoreographer(Choreographer::getForThread()); -} - -void AChoreographer_postFrameCallback(AChoreographer* choreographer, - AChoreographer_frameCallback callback, void* data) { - AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( - callback, nullptr, data, 0); -} -void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, - AChoreographer_frameCallback callback, void* data, long delayMillis) { - AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( - callback, nullptr, data, ms2ns(delayMillis)); -} -void AChoreographer_postFrameCallback64(AChoreographer* choreographer, - AChoreographer_frameCallback64 callback, void* data) { - AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( - nullptr, callback, data, 0); -} -void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, - AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) { - AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( - nullptr, callback, data, ms2ns(delayMillis)); -} -- cgit v1.2.3-59-g8ed1b From 26c5fbb065f4a814f2b0e22ae261e07204493aa9 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 14 Jan 2020 08:12:29 -0800 Subject: [AChoreographer] Lift refresh rate callbacks into NDK Bug: 136262896 Test: ChoreographerNativeTest Change-Id: Ica2fe31e511045e2007e7d1b3a129e1b8f26f3a7 --- native/android/libandroid.map.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'native/android') diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 203adfc749d2..e5c1f514b591 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -23,6 +23,8 @@ LIBANDROID { AChoreographer_postFrameCallbackDelayed; # introduced=24 AChoreographer_postFrameCallback64; # introduced=29 AChoreographer_postFrameCallbackDelayed64; # introduced=29 + AChoreographer_registerRefreshRateCallback; # introduced=30 + AChoreographer_unregisterRefreshRateCallback; # introduced=30 AConfiguration_copy; AConfiguration_delete; AConfiguration_diff; -- cgit v1.2.3-59-g8ed1b From 5af5d3077f921994b90e9bad89d393421f3cc160 Mon Sep 17 00:00:00 2001 From: Stan Iliev Date: Mon, 13 Jan 2020 11:29:18 -0500 Subject: Refactor TextureLayer JNI to use only APEX APIs Move ASurfaceTexture JNI implementation from libandroid to libnativedisplay. TextureLayer uses ASurfaceTexture_fromSurfaceTexture from libnativedisplay instead of libandroid_runtime code. libgui is no longer leaked through surface_texture_platform.h. DeferredLayerUpdater uses ASurfaceTexture_release instead of private ASurfaceTexture dtor. Test: pass CtsUiRenderingTestCases and CtsViewTestCases Bug: 147060713 Exempt-From-Owner-Approval: Changed only a header path in android_hardware_camera2_legacy_LegacyCameraDevice.cpp Change-Id: I9720d9c383f8120f9db116fd2b74fc241af84396 --- core/jni/android/graphics/SurfaceTexture.cpp | 6 +- ..._hardware_camera2_legacy_LegacyCameraDevice.cpp | 8 +-- core/jni/android_view_TextureLayer.cpp | 11 +--- libs/hwui/DeferredLayerUpdater.cpp | 3 + libs/hwui/DeferredLayerUpdater.h | 5 +- native/android/Android.bp | 3 +- native/android/surface_texture.cpp | 70 ---------------------- 7 files changed, 17 insertions(+), 89 deletions(-) delete mode 100644 native/android/surface_texture.cpp (limited to 'native/android') diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp index 1a9e8d077e21..2aca31733599 100644 --- a/core/jni/android/graphics/SurfaceTexture.cpp +++ b/core/jni/android/graphics/SurfaceTexture.cpp @@ -23,10 +23,10 @@ #include #include -#include -#include #include -#include +#include +#include +#include #include "core_jni_helpers.h" diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp index f2a51ad04885..8cf1d2cbfaae 100644 --- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp +++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp @@ -27,14 +27,14 @@ #include "android_runtime/android_view_Surface.h" #include "android_runtime/android_graphics_SurfaceTexture.h" -#include -#include #include #include -#include -#include +#include #include +#include #include +#include +#include #include #include diff --git a/core/jni/android_view_TextureLayer.cpp b/core/jni/android_view_TextureLayer.cpp index 5491a338023c..40f618025f99 100644 --- a/core/jni/android_view_TextureLayer.cpp +++ b/core/jni/android_view_TextureLayer.cpp @@ -19,12 +19,9 @@ #include "jni.h" #include +#include #include "core_jni_helpers.h" -#include -#include -#include -#include #include #include #include @@ -61,10 +58,8 @@ static void TextureLayer_setTransform(JNIEnv* env, jobject clazz, static void TextureLayer_setSurfaceTexture(JNIEnv* env, jobject clazz, jlong layerUpdaterPtr, jobject surface) { DeferredLayerUpdater* layer = reinterpret_cast(layerUpdaterPtr); - auto consumer = SurfaceTexture_getSurfaceTexture(env, surface); - auto producer = SurfaceTexture_getProducer(env, surface); - layer->setSurfaceTexture(AutoTextureRelease( - ASurfaceTexture_create(consumer, producer))); + ASurfaceTexture* surfaceTexture = ASurfaceTexture_fromSurfaceTexture(env, surface); + layer->setSurfaceTexture(AutoTextureRelease(surfaceTexture, &ASurfaceTexture_release)); } static void TextureLayer_updateSurfaceTexture(JNIEnv* env, jobject clazz, diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index d6b516fd5cf4..5a50245a3765 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -18,6 +18,8 @@ #include #include +// TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead. +#include #include "AutoBackendTextureRelease.h" #include "Matrix.h" #include "Properties.h" @@ -34,6 +36,7 @@ namespace uirenderer { DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState) : mRenderState(renderState) , mBlend(false) + , mSurfaceTexture(nullptr, [](ASurfaceTexture*) {}) , mTransform(nullptr) , mGLContextAttached(false) , mUpdateTexImage(false) diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index 289f65c22ad3..c44c0d537fa7 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -21,8 +21,7 @@ #include #include #include -// TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead. -#include +#include #include #include @@ -37,7 +36,7 @@ namespace uirenderer { class AutoBackendTextureRelease; class RenderState; -typedef std::unique_ptr AutoTextureRelease; +typedef std::unique_ptr AutoTextureRelease; // Container to hold the properties a layer should be set to at the start // of a render pass diff --git a/native/android/Android.bp b/native/android/Android.bp index 9d93c9b7b605..0c6f507787d9 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -47,7 +47,6 @@ cc_library_shared { "sensor.cpp", "sharedmem.cpp", "storage_manager.cpp", - "surface_texture.cpp", "surface_control.cpp", "system_fonts.cpp", "trace.cpp", @@ -70,6 +69,8 @@ cc_library_shared { "libnetd_client", "libhwui", "libxml2", + "libEGL", + "libGLESv2", "android.hardware.configstore@1.0", "android.hardware.configstore-utils", ], diff --git a/native/android/surface_texture.cpp b/native/android/surface_texture.cpp deleted file mode 100644 index 3049ec16e2d4..000000000000 --- a/native/android/surface_texture.cpp +++ /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. - */ - -#include -#include - -#define LOG_TAG "ASurfaceTexture" - -#include - -#include - -#include - -#include - -using namespace android; - -ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) { - if (!surfacetexture || !android_SurfaceTexture_isInstanceOf(env, surfacetexture)) { - return nullptr; - } - auto consumer = SurfaceTexture_getSurfaceTexture(env, surfacetexture); - auto producer = SurfaceTexture_getProducer(env, surfacetexture); - return ASurfaceTexture_create(consumer, producer); -} - -ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) { - sp surface = new Surface(st->producer); - ANativeWindow* win(surface.get()); - ANativeWindow_acquire(win); - return win; -} - -void ASurfaceTexture_release(ASurfaceTexture* st) { - delete st; -} - -int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t tex) { - return st->consumer->attachToContext(tex); -} - -int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) { - return st->consumer->detachFromContext(); -} - -int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) { - return st->consumer->updateTexImage(); -} - -void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) { - st->consumer->getTransformMatrix(mtx); -} - -int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) { - return st->consumer->getTimestamp(); -} -- cgit v1.2.3-59-g8ed1b From 6cf051ef8909be67f3fa7d6212a510d58e63df35 Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Tue, 14 Jan 2020 11:37:21 -0800 Subject: Add setFrameRate() api setFrameRate() is a new api in Android 11 that will enable apps to specify their intended frame rate. Bug: 143912624 Bug: 137287430 Test: Added a new CTS test - android.graphics.cts.SetFrameRateTest. Change-Id: I922573c0d704e2e0ce4cfc2a462f14dce8cb7a79 --- api/current.txt | 2 ++ core/java/android/view/Surface.java | 31 ++++++++++++++++++++++++++++++ core/java/android/view/SurfaceControl.java | 30 +++++++++++++++++++++++++++++ core/jni/android_view_Surface.cpp | 7 +++++++ core/jni/android_view_SurfaceControl.cpp | 10 ++++++++++ native/android/libandroid.map.txt | 1 + native/android/surface_control.cpp | 15 +++++++++++++++ 7 files changed, 96 insertions(+) (limited to 'native/android') diff --git a/api/current.txt b/api/current.txt index c4ac8336f330..c78f090edf28 100644 --- a/api/current.txt +++ b/api/current.txt @@ -52446,6 +52446,7 @@ package android.view { method public android.graphics.Canvas lockHardwareCanvas(); method public void readFromParcel(android.os.Parcel); method public void release(); + method public void setFrameRate(@FloatRange(from=0.0) float); method @Deprecated public void unlockCanvas(android.graphics.Canvas); method public void unlockCanvasAndPost(android.graphics.Canvas); method public void writeToParcel(android.os.Parcel, int); @@ -52489,6 +52490,7 @@ package android.view { method @NonNull public android.view.SurfaceControl.Transaction reparent(@NonNull android.view.SurfaceControl, @Nullable android.view.SurfaceControl); method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float); method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int); + method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float); method @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int); method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int); method @NonNull public android.view.SurfaceControl.Transaction setVisibility(@NonNull android.view.SurfaceControl, boolean); diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 7707ad163b85..a6b7c33de3d9 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; @@ -88,6 +89,8 @@ public class Surface implements Parcelable { private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled); private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled); + private static native int nativeSetFrameRate(long nativeObject, float frameRate); + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override @@ -840,6 +843,34 @@ public class Surface implements Parcelable { return mIsAutoRefreshEnabled; } + /** + * Sets the intended frame rate for this surface. + * + * On devices that are capable of running the display at different refresh rates, the + * system may choose a display refresh rate to better match this surface's frame + * rate. Usage of this API won't introduce frame rate throttling, or affect other + * aspects of the application's frame production pipeline. However, because the system + * may change the display refresh rate, calls to this function may result in changes + * to Choreographer callback timings, and changes to the time interval at which the + * system releases buffers back to the application. + * + * Note that this only has an effect for surfaces presented on the display. If this + * surface is consumed by something other than the system compositor, e.g. a media + * codec, this call has no effect. + * + * @param frameRate The intended frame rate of this surface. 0 is a special value that + * indicates the app will accept the system's choice for the display frame rate, which + * is the default behavior if this function isn't called. The frameRate param does + * *not* need to be a valid refresh rate for this device's display - e.g., it's fine + * to pass 30fps to a device that can only run the display at 60fps. + */ + public void setFrameRate(@FloatRange(from = 0.0) float frameRate) { + int error = nativeSetFrameRate(mNativeObject, frameRate); + if (error != 0) { + throw new RuntimeException("Failed to set frame rate on Surface"); + } + } + /** * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or * when a SurfaceTexture could not successfully be allocated. diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index bcc9e41b8ab0..f7b87cce7338 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -211,6 +211,9 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetGlobalShadowSettings(@Size(4) float[] ambientColor, @Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius); + private static native void nativeSetFrameRate( + long transactionObj, long nativeObject, float frameRate); + private final CloseGuard mCloseGuard = CloseGuard.get(); private String mName; /** @@ -2786,6 +2789,33 @@ public final class SurfaceControl implements Parcelable { return this; } + /** + * Sets the intended frame rate for the surface {@link SurfaceControl}. + * + * On devices that are capable of running the display at different refresh rates, the system + * may choose a display refresh rate to better match this surface's frame rate. Usage of + * this API won't directly affect the application's frame production pipeline. However, + * because the system may change the display refresh rate, calls to this function may result + * in changes to Choreographer callback timings, and changes to the time interval at which + * the system releases buffers back to the application. + * + * @param sc The SurfaceControl to specify the frame rate of. + * @param frameRate The intended frame rate for this surface. 0 is a special value that + * indicates the app will accept the system's choice for the display frame + * rate, which is the default behavior if this function isn't called. The + * frameRate param does *not* need to be a valid refresh rate for this + * device's display - e.g., it's fine to pass 30fps to a device that can + * only run the display at 60fps. + * @return This transaction object. + */ + @NonNull + public Transaction setFrameRate( + @NonNull SurfaceControl sc, @FloatRange(from = 0.0) float frameRate) { + checkPreconditions(sc); + nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate); + return this; + } + /** * Merge the other transaction into this transaction, clearing the * other transaction as if it had been applied. diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 01b5920755fa..b01083bba643 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -413,6 +413,12 @@ static jint nativeSetAutoRefreshEnabled(JNIEnv* env, jclass clazz, jlong nativeO return anw->perform(surface, NATIVE_WINDOW_SET_AUTO_REFRESH, int(enabled)); } +static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate) { + Surface* surface = reinterpret_cast(nativeObject); + ANativeWindow* anw = static_cast(surface); + return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, float(frameRate)); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gSurfaceMethods[] = { @@ -447,6 +453,7 @@ static const JNINativeMethod gSurfaceMethods[] = { (void*)nativeAttachAndQueueBufferWithColorSpace}, {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled}, {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled}, + {"nativeSetFrameRate", "(JF)I", (void*)nativeSetFrameRate}, }; int register_android_view_Surface(JNIEnv* env) diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index e0f9571472da..2b9d45431582 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -584,6 +584,14 @@ static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionOb transaction->setShadowRadius(ctrl, shadowRadius); } +static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject, + jfloat frameRate) { + auto transaction = reinterpret_cast(transactionObj); + + const auto ctrl = reinterpret_cast(nativeObject); + transaction->setFrameRate(ctrl, frameRate); +} + static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) { const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds(); jlongArray array = env->NewLongArray(displayIds.size()); @@ -1383,6 +1391,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetLayerStack }, {"nativeSetShadowRadius", "(JJF)V", (void*)nativeSetShadowRadius }, + {"nativeSetFrameRate", "(JJF)V", + (void*)nativeSetFrameRate }, {"nativeGetPhysicalDisplayIds", "()[J", (void*)nativeGetPhysicalDisplayIds }, {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;", diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 203adfc749d2..97b861b390ad 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -240,6 +240,7 @@ LIBANDROID { ASurfaceTransaction_setColor; # introduced=29 ASurfaceTransaction_setDamageRegion; # introduced=29 ASurfaceTransaction_setDesiredPresentTime; # introduced=29 + ASurfaceTransaction_setFrameRate; # introduced=30 ASurfaceTransaction_setGeometry; # introduced=29 ASurfaceTransaction_setHdrMetadata_cta861_3; # introduced=29 ASurfaceTransaction_setHdrMetadata_smpte2086; # introduced=29 diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index b34b31ac8439..392c9f6404ba 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -545,3 +545,18 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction, transaction->setBackgroundColor(surfaceControl, color, alpha, static_cast(dataspace)); } + +void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* aSurfaceTransaction, + ASurfaceControl* aSurfaceControl, float frameRate) { + CHECK_NOT_NULL(aSurfaceTransaction); + CHECK_NOT_NULL(aSurfaceControl); + + sp surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + if (frameRate < 0) { + ALOGE("Failed to set frame ate - invalid frame rate"); + return; + } + + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + transaction->setFrameRate(surfaceControl, frameRate); +} -- cgit v1.2.3-59-g8ed1b From d6a222eab0d5095bb6736cc6acbe25c57eca1f11 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Wed, 29 Jan 2020 14:27:09 -0800 Subject: Pass back frame event stats Adding frame event stats to SurfaceControlStats Not exposing to ASurfaceControlStats Bug: 141939081 Test: build, boot Change-Id: If64056514be6b5161d52f5e8c2cc499bd8389099 --- native/android/surface_control.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'native/android') diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index 392c9f6404ba..ba793e83f1fb 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -294,7 +294,7 @@ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* aSurfaceTransaction, auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats; - for (const auto& [surfaceControl, acquireTime, previousReleaseFence, transformHint] : surfaceControlStats) { + for (const auto& [surfaceControl, latchTime, acquireTime, presentFence, previousReleaseFence, transformHint, frameEvents] : surfaceControlStats) { ASurfaceControl* aSurfaceControl = reinterpret_cast(surfaceControl.get()); aSurfaceControlStats[aSurfaceControl].acquireTime = acquireTime; aSurfaceControlStats[aSurfaceControl].previousReleaseFence = previousReleaseFence; -- cgit v1.2.3-59-g8ed1b From a2b78e4d6b6df1950de9995798027a7e79b64773 Mon Sep 17 00:00:00 2001 From: Tej Singh Date: Wed, 29 Jan 2020 19:07:38 -0800 Subject: Create libstats_jni This cl creates libstats_jni, puts the android_util_StatsLog class in it to implement the jni StatsLog.writeImpl() call, and puts the library in the statsd apex. Right now, it does NOT load the library properly and therefore the library is still in the platform. It needs to be removed from the platform. Test: boots Test: adb shell cmd stats print-logs shows logs still flow Bug: 147315667 Change-Id: I0a06b66d4640d00ee75bc273423b33dafc944b05 --- apex/statsd/Android.bp | 35 +++++++++++++- apex/statsd/jni/android_util_StatsLog.cpp | 80 +++++++++++++++++++++++++++++++ core/jni/Android.bp | 1 - core/jni/AndroidRuntime.cpp | 2 - core/jni/android_util_StatsLog.cpp | 63 ------------------------ native/android/Android.bp | 1 + 6 files changed, 114 insertions(+), 68 deletions(-) create mode 100644 apex/statsd/jni/android_util_StatsLog.cpp delete mode 100644 core/jni/android_util_StatsLog.cpp (limited to 'native/android') diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp index 09ca1d257460..1f9f18cd051a 100644 --- a/apex/statsd/Android.bp +++ b/apex/statsd/Android.bp @@ -19,8 +19,9 @@ apex { } apex_defaults { - // libc.so and libcutils.so are included in the apex - // native_shared_libs: ["libc", "libcutils"], + native_shared_libs: [ + "libstats_jni", + ], // binaries: ["vold"], java_libs: [ "framework-statsd", @@ -44,3 +45,33 @@ android_app_certificate { // com.android.os.statsd.pk8 (the private key) certificate: "com.android.os.statsd", } + + +// JNI library for StatsLog.write +cc_library_shared { + name: "libstats_jni", + srcs: ["jni/**/*.cpp"], + shared_libs: [ + "libnativehelper", // Has stable abi - should not be copied into apex. + "liblog", // Has a stable abi - should not be copied into apex. + ], + static_libs: [ + //TODO: make shared - need libstatssocket to also live in the apex. + "libstatssocket", + "libcutils", // TODO: remove - needed by libstatssocket + ], + //TODO: is libc++_static correct? + stl: "libc++_static", + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + "-Wno-unused-parameter", + ], + apex_available: [ + "com.android.os.statsd", + "test_com.android.os.statsd", + //TODO (b/148620413): remove platform. + "//apex_available:platform", + ], +} \ No newline at end of file diff --git a/apex/statsd/jni/android_util_StatsLog.cpp b/apex/statsd/jni/android_util_StatsLog.cpp new file mode 100644 index 000000000000..9d410eb1f836 --- /dev/null +++ b/apex/statsd/jni/android_util_StatsLog.cpp @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#define LOG_NAMESPACE "StatsLog.tag." +#define LOG_TAG "StatsLog_println" + +#include "jni.h" +#include +#include +#include "stats_buffer_writer.h" + +namespace android { + +static void android_util_StatsLog_write(JNIEnv* env, jobject clazz, jbyteArray buf, jint size, + jint atomId) { + if (buf == NULL) { + return; + } + jint actualSize = env->GetArrayLength(buf); + if (actualSize < size) { + return; + } + + jbyte* bufferArray = env->GetByteArrayElements(buf, NULL); + if (bufferArray == NULL) { + return; + } + + write_buffer_to_statsd((void*) bufferArray, size, atomId); + + env->ReleaseByteArrayElements(buf, bufferArray, 0); +} + +/* + * JNI registration. + */ +static const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "writeImpl", "([BII)V", (void*) android_util_StatsLog_write }, +}; + +int register_android_util_StatsLog(JNIEnv* env) +{ + return jniRegisterNativeMethods(env, "android/util/StatsLog", gMethods, NELEM(gMethods)); +} +}; // namespace android + +/* + * JNI Initialization + */ +jint JNI_OnLoad(JavaVM* jvm, void* reserved) { + JNIEnv* e; + int status; + + ALOGV("statsd : loading JNI\n"); + // Check JNI version + if (jvm->GetEnv((void**)&e, JNI_VERSION_1_4)) { + ALOGE("JNI version mismatch error"); + return JNI_ERR; + } + status = android::register_android_util_StatsLog(e); + if (status < 0) { + ALOGE("jni statsd registration failure, status: %d", status); + return JNI_ERR; + } + return JNI_VERSION_1_4; +} diff --git a/core/jni/Android.bp b/core/jni/Android.bp index a2f514a85ff8..c04efa3be596 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -147,7 +147,6 @@ cc_library_shared { "android_service_DataLoaderService.cpp", "android_util_AssetManager.cpp", "android_util_Binder.cpp", - "android_util_StatsLog.cpp", "android_util_MemoryIntArray.cpp", "android_util_Process.cpp", "android_util_StringBlock.cpp", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 9783b655e057..790ac080e705 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -108,7 +108,6 @@ namespace android { extern int register_android_app_admin_SecurityLog(JNIEnv* env); extern int register_android_content_AssetManager(JNIEnv* env); extern int register_android_util_EventLog(JNIEnv* env); -extern int register_android_util_StatsLog(JNIEnv* env); extern int register_android_util_StatsLogInternal(JNIEnv* env); extern int register_android_util_Log(JNIEnv* env); extern int register_android_util_MemoryIntArray(JNIEnv* env); @@ -1441,7 +1440,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), REG_JNI(register_android_util_MemoryIntArray), - REG_JNI(register_android_util_StatsLog), REG_JNI(register_android_util_StatsLogInternal), REG_JNI(register_android_app_admin_SecurityLog), REG_JNI(register_android_content_AssetManager), diff --git a/core/jni/android_util_StatsLog.cpp b/core/jni/android_util_StatsLog.cpp deleted file mode 100644 index 9225fc2839d0..000000000000 --- a/core/jni/android_util_StatsLog.cpp +++ /dev/null @@ -1,63 +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. - */ - -#define LOG_NAMESPACE "StatsLog.tag." -#define LOG_TAG "StatsLog_println" - -#include - -#include "jni.h" -#include -#include "utils/misc.h" -#include "core_jni_helpers.h" -#include "stats_buffer_writer.h" - -namespace android { - -static void android_util_StatsLog_write(JNIEnv* env, jobject clazz, jbyteArray buf, jint size, - jint atomId) { - if (buf == NULL) { - return; - } - jint actualSize = env->GetArrayLength(buf); - if (actualSize < size) { - return; - } - - jbyte* bufferArray = env->GetByteArrayElements(buf, NULL); - if (bufferArray == NULL) { - return; - } - - write_buffer_to_statsd((void*) bufferArray, size, atomId); - - env->ReleaseByteArrayElements(buf, bufferArray, 0); -} - -/* - * JNI registration. - */ -static const JNINativeMethod gMethods[] = { - /* name, signature, funcPtr */ - { "writeImpl", "([BII)V", (void*) android_util_StatsLog_write }, -}; - -int register_android_util_StatsLog(JNIEnv* env) -{ - return RegisterMethodsOrDie(env, "android/util/StatsLog", gMethods, NELEM(gMethods)); -} - -}; // namespace android diff --git a/native/android/Android.bp b/native/android/Android.bp index 0c6f507787d9..34ab7a0a0770 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -64,6 +64,7 @@ cc_library_shared { "libgui", "libharfbuzz_ng", // Only for including hb.h via minikin "libsensor", + "libstats_jni", "libandroid_runtime", "libminikin", "libnetd_client", -- cgit v1.2.3-59-g8ed1b From 93b4e99d9b975b64c5cae761e67001e664fa4a1a Mon Sep 17 00:00:00 2001 From: Muhammad Qureshi Date: Sun, 2 Feb 2020 08:25:44 -0800 Subject: Fix StatsLog JNI registration Re-add StatsLog JNI regsitration in AndroidRuntime.cpp. This will have to be revisited once StatsLog is moved into statsd apex. Test: m Test: fastboot flashall Test: adb logcat "*:E" Change-Id: I233a527d00d524cbc2edaed7c2be76ea1c212b29 --- core/jni/Android.bp | 1 + core/jni/AndroidRuntime.cpp | 2 ++ native/android/Android.bp | 1 - 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'native/android') diff --git a/core/jni/Android.bp b/core/jni/Android.bp index c04efa3be596..212630f13ece 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -268,6 +268,7 @@ cc_library_shared { "libnativewindow", "libdl", "libdl_android", + "libstats_jni", "libstatslog", "server_configurable_flags", ], diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 790ac080e705..9783b655e057 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -108,6 +108,7 @@ namespace android { extern int register_android_app_admin_SecurityLog(JNIEnv* env); extern int register_android_content_AssetManager(JNIEnv* env); extern int register_android_util_EventLog(JNIEnv* env); +extern int register_android_util_StatsLog(JNIEnv* env); extern int register_android_util_StatsLogInternal(JNIEnv* env); extern int register_android_util_Log(JNIEnv* env); extern int register_android_util_MemoryIntArray(JNIEnv* env); @@ -1440,6 +1441,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), REG_JNI(register_android_util_MemoryIntArray), + REG_JNI(register_android_util_StatsLog), REG_JNI(register_android_util_StatsLogInternal), REG_JNI(register_android_app_admin_SecurityLog), REG_JNI(register_android_content_AssetManager), diff --git a/native/android/Android.bp b/native/android/Android.bp index 34ab7a0a0770..0c6f507787d9 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -64,7 +64,6 @@ cc_library_shared { "libgui", "libharfbuzz_ng", // Only for including hb.h via minikin "libsensor", - "libstats_jni", "libandroid_runtime", "libminikin", "libnetd_client", -- cgit v1.2.3-59-g8ed1b From cf07528a0ef5037fee55da3a577f2b9d440dd1ec Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 15 Jan 2020 17:35:58 -0800 Subject: New VerifiedInputEvent api The Verified{Input/Key/Motion}Event api are the same as {Input/Key/Motion}Event api. The VerifiedMotion class is the same as the MotionEvent class, but contains less information. It only contains the information that the system is able to verify. Same applies to VerifiedKeyEvent. The class VerifiedInputEvent contains common information applicable to both Key and Motion. Test: atest VerifiedKeyEventTest VerifiedMotionEventTest Bug: 134977432 Change-Id: I4770104eb4c025263da7efeea9c7a658dff74ac9 --- api/current.txt | 33 ++ .../java/android/hardware/input/IInputManager.aidl | 3 + core/java/android/hardware/input/InputManager.java | 23 ++ core/java/android/view/VerifiedInputEvent.aidl | 19 + core/java/android/view/VerifiedInputEvent.java | 162 ++++++++ core/java/android/view/VerifiedKeyEvent.aidl | 19 + core/java/android/view/VerifiedKeyEvent.java | 414 +++++++++++++++++++++ core/java/android/view/VerifiedMotionEvent.aidl | 19 + core/java/android/view/VerifiedMotionEvent.java | 393 +++++++++++++++++++ core/jni/Android.bp | 2 + core/jni/android_view_KeyEvent.cpp | 2 +- core/jni/android_view_VerifiedKeyEvent.cpp | 39 ++ core/jni/android_view_VerifiedKeyEvent.h | 32 ++ core/jni/android_view_VerifiedMotionEvent.cpp | 39 ++ core/jni/android_view_VerifiedMotionEvent.h | 32 ++ core/tests/coretests/Android.bp | 1 + .../src/android/view/VerifiedKeyEventTest.kt | 165 ++++++++ .../src/android/view/VerifiedMotionEventTest.kt | 185 +++++++++ native/android/Android.bp | 1 + .../android/server/input/InputManagerService.java | 7 + ...om_android_server_input_InputManagerService.cpp | 188 +++++----- 21 files changed, 1691 insertions(+), 87 deletions(-) create mode 100644 core/java/android/view/VerifiedInputEvent.aidl create mode 100644 core/java/android/view/VerifiedInputEvent.java create mode 100644 core/java/android/view/VerifiedKeyEvent.aidl create mode 100644 core/java/android/view/VerifiedKeyEvent.java create mode 100644 core/java/android/view/VerifiedMotionEvent.aidl create mode 100644 core/java/android/view/VerifiedMotionEvent.java create mode 100644 core/jni/android_view_VerifiedKeyEvent.cpp create mode 100644 core/jni/android_view_VerifiedKeyEvent.h create mode 100644 core/jni/android_view_VerifiedMotionEvent.cpp create mode 100644 core/jni/android_view_VerifiedMotionEvent.h create mode 100644 core/tests/coretests/src/android/view/VerifiedKeyEventTest.kt create mode 100644 core/tests/coretests/src/android/view/VerifiedMotionEventTest.kt (limited to 'native/android') diff --git a/api/current.txt b/api/current.txt index 826d409b0a2d..708e17b5e6e2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -18109,6 +18109,7 @@ package android.hardware.input { method public int[] getInputDeviceIds(); method public void registerInputDeviceListener(android.hardware.input.InputManager.InputDeviceListener, android.os.Handler); method public void unregisterInputDeviceListener(android.hardware.input.InputManager.InputDeviceListener); + method @Nullable public android.view.VerifiedInputEvent verifyInputEvent(@NonNull android.view.InputEvent); field public static final String ACTION_QUERY_KEYBOARD_LAYOUTS = "android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS"; field public static final String META_DATA_KEYBOARD_LAYOUTS = "android.hardware.input.metadata.KEYBOARD_LAYOUTS"; } @@ -53318,6 +53319,38 @@ package android.view { method public void recycle(); } + public abstract class VerifiedInputEvent implements android.os.Parcelable { + method public int describeContents(); + method public int getDeviceId(); + method public int getDisplayId(); + method public long getEventTimeNanos(); + method public int getSource(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public final class VerifiedKeyEvent extends android.view.VerifiedInputEvent implements android.os.Parcelable { + method public int getAction(); + method public long getDownTimeNanos(); + method @Nullable public Boolean getFlag(int); + method public int getKeyCode(); + method public int getMetaState(); + method public int getRepeatCount(); + method public int getScanCode(); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public final class VerifiedMotionEvent extends android.view.VerifiedInputEvent implements android.os.Parcelable { + method public int getActionMasked(); + method public int getButtonState(); + method public long getDownTimeNanos(); + method @Nullable public Boolean getFlag(int); + method public int getMetaState(); + method public float getRawX(); + method public float getRawY(); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback { ctor public View(android.content.Context); ctor public View(android.content.Context, @Nullable android.util.AttributeSet); diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 6e1987c47d20..fb44b0b66fd8 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -27,6 +27,7 @@ import android.view.InputDevice; import android.view.InputEvent; import android.view.InputMonitor; import android.view.PointerIcon; +import android.view.VerifiedInputEvent; /** @hide */ interface IInputManager { @@ -50,6 +51,8 @@ interface IInputManager { @UnsupportedAppUsage boolean injectInputEvent(in InputEvent ev, int mode); + VerifiedInputEvent verifyInputEvent(in InputEvent ev); + // Calibrate input device position TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor, int rotation); void setTouchCalibrationForInputDevice(String inputDeviceDescriptor, int rotation, diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 83f01a5dca35..fb27081a5512 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -18,6 +18,7 @@ package android.hardware.input; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; @@ -45,6 +46,7 @@ import android.view.InputEvent; import android.view.InputMonitor; import android.view.MotionEvent; import android.view.PointerIcon; +import android.view.VerifiedInputEvent; import com.android.internal.os.SomeArgs; @@ -906,6 +908,27 @@ public final class InputManager { } } + /** + * Verify the details of an {@link android.view.InputEvent} that came from the system. + * If the event did not come from the system, or its details could not be verified, then this + * will return {@code null}. Receiving {@code null} does not mean that the event did not + * originate from the system, just that we were unable to verify it. This can + * happen for a number of reasons during normal operation. + * + * @param event The {@link android.view.InputEvent} to check + * + * @return {@link android.view.VerifiedInputEvent}, which is a subset of the provided + * {@link android.view.InputEvent} + * {@code null} if the event could not be verified. + */ + public @Nullable VerifiedInputEvent verifyInputEvent(@NonNull InputEvent event) { + try { + return mIm.verifyInputEvent(event); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + /** * Changes the mouse pointer's icon shape into the specified id. * diff --git a/core/java/android/view/VerifiedInputEvent.aidl b/core/java/android/view/VerifiedInputEvent.aidl new file mode 100644 index 000000000000..41608d8971f7 --- /dev/null +++ b/core/java/android/view/VerifiedInputEvent.aidl @@ -0,0 +1,19 @@ +/* + * 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.view; + +parcelable VerifiedInputEvent; diff --git a/core/java/android/view/VerifiedInputEvent.java b/core/java/android/view/VerifiedInputEvent.java new file mode 100644 index 000000000000..531b3ed39fc3 --- /dev/null +++ b/core/java/android/view/VerifiedInputEvent.java @@ -0,0 +1,162 @@ +/* + * 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.view; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; + + +/** + * Base class for verified events. + * Verified events contain the subset of an InputEvent that the system can verify. + * Data contained inside VerifiedInputEvent's should be considered trusted and contain only + * the original event data that first came from the system. + * + * @see android.hardware.input.InputManager#verifyInputEvent(InputEvent) + */ +@SuppressLint("ParcelNotFinal") +public abstract class VerifiedInputEvent implements Parcelable { + private static final String TAG = "VerifiedInputEvent"; + + /** @hide */ + protected static final int VERIFIED_KEY = 1; + /** @hide */ + protected static final int VERIFIED_MOTION = 2; + + /** @hide */ + @Retention(SOURCE) + @IntDef(prefix = "VERIFIED", value = {VERIFIED_KEY, VERIFIED_MOTION}) + public @interface VerifiedInputEventType {}; + + @VerifiedInputEventType + private int mType; + + private int mDeviceId; + private long mEventTimeNanos; + private int mSource; + private int mDisplayId; + + /** @hide */ + protected VerifiedInputEvent(int type, int deviceId, long eventTimeNanos, int source, + int displayId) { + mType = type; + mDeviceId = deviceId; + mEventTimeNanos = eventTimeNanos; + mSource = source; + mDisplayId = displayId; + } + /** @hide */ + protected VerifiedInputEvent(@NonNull Parcel in, int expectedType) { + mType = in.readInt(); + if (mType != expectedType) { + throw new IllegalArgumentException("Unexpected input event type token in parcel."); + } + mDeviceId = in.readInt(); + mEventTimeNanos = in.readLong(); + mSource = in.readInt(); + mDisplayId = in.readInt(); + } + + /** + * Get the id of the device that generated this event. + * + * @see InputEvent#getDeviceId() + */ + public int getDeviceId() { + return mDeviceId; + } + + /** + * Get the time this event occurred, in the {@link android.os.SystemClock#uptimeMillis()} + * time base. + * + * @see InputEvent#getEventTime() + * @see KeyEvent#getEventTimeNano() + * @see MotionEvent#getEventTimeNano() + */ + @SuppressLint("MethodNameUnits") + public long getEventTimeNanos() { + return mEventTimeNanos; + } + + /** + * Get the source of the event. + * + * @see InputEvent#getSource() + */ + public int getSource() { + return mSource; + } + + /** + * Get the display id that is associated with this event. + * + * @see Display#getDisplayId() + */ + public int getDisplayId() { + return mDisplayId; + } + + /** {@inheritDoc} */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mType); + dest.writeInt(mDeviceId); + dest.writeLong(mEventTimeNanos); + dest.writeInt(mSource); + dest.writeInt(mDisplayId); + } + + /** {@inheritDoc} */ + @Override + public int describeContents() { + return 0; + } + + private static int peekInt(@NonNull Parcel parcel) { + final int initialDataPosition = parcel.dataPosition(); + int data = parcel.readInt(); + parcel.setDataPosition(initialDataPosition); + return data; + } + + public static final @NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public VerifiedInputEvent[] newArray(int size) { + return new VerifiedInputEvent[size]; + } + + @Override + public VerifiedInputEvent createFromParcel(@NonNull Parcel in) { + final int type = peekInt(in); + if (type == VERIFIED_KEY) { + return VerifiedKeyEvent.CREATOR.createFromParcel(in); + } else if (type == VERIFIED_MOTION) { + return VerifiedMotionEvent.CREATOR.createFromParcel(in); + } + throw new IllegalArgumentException("Unexpected input event type in parcel."); + } + }; +} diff --git a/core/java/android/view/VerifiedKeyEvent.aidl b/core/java/android/view/VerifiedKeyEvent.aidl new file mode 100644 index 000000000000..2d6c3a481b37 --- /dev/null +++ b/core/java/android/view/VerifiedKeyEvent.aidl @@ -0,0 +1,19 @@ +/* + * 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.view; + +parcelable VerifiedKeyEvent; diff --git a/core/java/android/view/VerifiedKeyEvent.java b/core/java/android/view/VerifiedKeyEvent.java new file mode 100644 index 000000000000..dc5b7cc1e13a --- /dev/null +++ b/core/java/android/view/VerifiedKeyEvent.java @@ -0,0 +1,414 @@ +/* + * 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.view; + +import static android.view.KeyEvent.FLAG_CANCELED; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +import java.lang.annotation.Retention; + +/** + * KeyEvent that has been verified by the system. + * The data contained in this class is always a subset of a {@link KeyEvent}. Use this class to + * check which data has been confirmed by the system to be authentic. + * + * Most applications do not need to use this class. + * + * {@see android.hardware.input.InputManager#verifyInputEvent} + */ +@DataClass(genHiddenConstructor = true, genEqualsHashCode = true) +public final class VerifiedKeyEvent extends VerifiedInputEvent implements Parcelable { + private static final String TAG = "VerifiedKeyEvent"; + + /** @hide */ + @Retention(SOURCE) + @IntDef({KeyEvent.ACTION_DOWN, KeyEvent.ACTION_UP}) + public @interface KeyEventAction {}; + + /** + * The action of this key event. May be either {@link KeyEvent#ACTION_DOWN} or + * {@link KeyEvent#ACTION_UP}. + * + * @see KeyEvent#getAction() + */ + @KeyEventAction + private int mAction; + + /** + * Retrieve the time of the most recent key down event, in the + * {@link android.os.SystemClock#uptimeMillis} time base, but in nanoseconds. If this + * is a down event, this will be the same as {@link VerifiedInputEvent#getEventTimeNanos()}. + * + * @see KeyEvent#getDownTime() + */ + @SuppressLint({"MethodNameUnits"}) + private long mDownTimeNanos; + + /** + * Returns the flags for this key event. + * + * @see KeyEvent#getFlags() + * @see KeyEvent#FLAG_CANCELED + * + * @hide + */ + private int mFlags; + + /** + * Retrieve the key code of the key event. + * + * @see KeyEvent#getKeyCode() + */ + private int mKeyCode; + + /** + * Retrieve the hardware key id of this key event. These values are not reliable + * and vary from device to device. + * + * @see KeyEvent#getScanCode() + */ + private int mScanCode; + + /** + *

Returns the state of the meta keys.

+ * + * @return an integer in which each bit set to 1 represents a pressed meta key + * @see KeyEvent#getMetaState() + */ + private int mMetaState; + + /** + * Retrieve the repeat count of the event. For key down events, this is the number of times + * the key has repeated with the first down starting at 0 and counting up from there. + * For key up events, this is always equal to zero. For multiple key events, + * this is the number of down/up pairs that have occurred. + */ + private int mRepeatCount; + + /** + * Get a specific flag of this key event, if possible. Return null if the flag value could + * not be checked. + * + * @param flag the flag of interest + * @return Boolean(true) if the key event has the requested flag + * Boolean(false) if the key event does not have the requested flag + * null if the flag value could not be checked + * + * @see KeyEvent#getFlags() + * @see KeyEvent#FLAG_CANCELED + */ + public @Nullable Boolean getFlag(int flag) { + switch(flag) { + // InputDispatcher only verifies a subset of the KeyEvent flags. + // These values must be kept in sync with Input.cpp + case FLAG_CANCELED: + return (mFlags & flag) != 0; + } + return null; + } + + // The codegen tool doesn't fully support subclasses, since it works on a per-file basis. + // To modify this file: + // 1. run codegen on this file + // 2. edit the constructor signature + // 3. add the "super" call for constructor that receives a Parcel + // 4. add the "super" call to the writeToParcel method + // 5. Update "equals" and "hashcode" methods to include VerifiedInputEvent fields + // 6. Edit "inputSignatures" to ensure KeyEventAction is properly qualified + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/VerifiedKeyEvent.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new VerifiedKeyEvent. + * + * @param action + * The action of this key event. May be either {@link KeyEvent#ACTION_DOWN} or + * {@link KeyEvent#ACTION_UP}. + * @param downTimeNanos + * Retrieve the time of the most recent key down event, in the + * {@link android.os.SystemClock#uptimeMillis} time base, but in nanoseconds. If this + * is a down event, this will be the same as {@link VerifiedInputEvent#getEventTimeNanos()}. + * @param flags + * Returns the flags for this key event. + * @param keyCode + * Retrieve the key code of the key event. + * @param scanCode + * Retrieve the hardware key id of this key event. These values are not reliable + * and vary from device to device. + * @param metaState + *

Returns the state of the meta keys.

+ * @param repeatCount + * Retrieve the repeat count of the event. For key down events, this is the number of times + * the key has repeated with the first down starting at 0 and counting up from there. + * For key up events, this is always equal to zero. For multiple key events, + * this is the number of down/up pairs that have occurred. + * @hide + */ + @DataClass.Generated.Member + public VerifiedKeyEvent( + int deviceId, + long eventTimeNanos, + int source, + int displayId, + @KeyEventAction int action, + @SuppressLint({"MethodNameUnits"}) long downTimeNanos, + int flags, + int keyCode, + int scanCode, + int metaState, + int repeatCount) { + super(VERIFIED_KEY, deviceId, eventTimeNanos, source, displayId); + this.mAction = action; + com.android.internal.util.AnnotationValidations.validate( + KeyEventAction.class, null, mAction); + this.mDownTimeNanos = downTimeNanos; + com.android.internal.util.AnnotationValidations.validate( + SuppressLint.class, null, mDownTimeNanos, + "value", "MethodNameUnits"); + this.mFlags = flags; + this.mKeyCode = keyCode; + this.mScanCode = scanCode; + this.mMetaState = metaState; + this.mRepeatCount = repeatCount; + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The action of this key event. May be either {@link KeyEvent#ACTION_DOWN} or + * {@link KeyEvent#ACTION_UP}. + * + * @see KeyEvent#getAction() + */ + @DataClass.Generated.Member + public @KeyEventAction int getAction() { + return mAction; + } + + /** + * Retrieve the time of the most recent key down event, in the + * {@link android.os.SystemClock#uptimeMillis} time base, but in nanoseconds. If this + * is a down event, this will be the same as {@link VerifiedInputEvent#getEventTimeNanos()}. + * + * @see KeyEvent#getDownTime() + */ + @DataClass.Generated.Member + public @SuppressLint({"MethodNameUnits"}) long getDownTimeNanos() { + return mDownTimeNanos; + } + + /** + * Returns the flags for this key event. + * + * @see KeyEvent#getFlags() + * @see KeyEvent#FLAG_CANCELED + * @hide + */ + @DataClass.Generated.Member + public int getFlags() { + return mFlags; + } + + /** + * Retrieve the key code of the key event. + * + * @see KeyEvent#getKeyCode() + */ + @DataClass.Generated.Member + public int getKeyCode() { + return mKeyCode; + } + + /** + * Retrieve the hardware key id of this key event. These values are not reliable + * and vary from device to device. + * + * @see KeyEvent#getScanCode() + */ + @DataClass.Generated.Member + public int getScanCode() { + return mScanCode; + } + + /** + *

Returns the state of the meta keys.

+ * + * @return an integer in which each bit set to 1 represents a pressed meta key + * @see KeyEvent#getMetaState() + */ + @DataClass.Generated.Member + public int getMetaState() { + return mMetaState; + } + + /** + * Retrieve the repeat count of the event. For key down events, this is the number of times + * the key has repeated with the first down starting at 0 and counting up from there. + * For key up events, this is always equal to zero. For multiple key events, + * this is the number of down/up pairs that have occurred. + */ + @DataClass.Generated.Member + public int getRepeatCount() { + return mRepeatCount; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(VerifiedKeyEvent other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + VerifiedKeyEvent that = (VerifiedKeyEvent) o; + //noinspection PointlessBooleanExpression + return true + && getDeviceId() == that.getDeviceId() + && getEventTimeNanos() == that.getEventTimeNanos() + && getSource() == that.getSource() + && getDisplayId() == that.getDisplayId() + && mAction == that.mAction + && mDownTimeNanos == that.mDownTimeNanos + && mFlags == that.mFlags + && mKeyCode == that.mKeyCode + && mScanCode == that.mScanCode + && mMetaState == that.mMetaState + && mRepeatCount == that.mRepeatCount; + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + getDeviceId(); + _hash = 31 * _hash + Long.hashCode(getEventTimeNanos()); + _hash = 31 * _hash + getSource(); + _hash = 31 * _hash + getDisplayId(); + _hash = 31 * _hash + mAction; + _hash = 31 * _hash + Long.hashCode(mDownTimeNanos); + _hash = 31 * _hash + mFlags; + _hash = 31 * _hash + mKeyCode; + _hash = 31 * _hash + mScanCode; + _hash = 31 * _hash + mMetaState; + _hash = 31 * _hash + mRepeatCount; + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@android.annotation.NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + super.writeToParcel(dest, flags); + dest.writeInt(mAction); + dest.writeLong(mDownTimeNanos); + dest.writeInt(mFlags); + dest.writeInt(mKeyCode); + dest.writeInt(mScanCode); + dest.writeInt(mMetaState); + dest.writeInt(mRepeatCount); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ VerifiedKeyEvent(@android.annotation.NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + super(in, VERIFIED_KEY); + int action = in.readInt(); + long downTimeNanos = in.readLong(); + int flags = in.readInt(); + int keyCode = in.readInt(); + int scanCode = in.readInt(); + int metaState = in.readInt(); + int repeatCount = in.readInt(); + + this.mAction = action; + com.android.internal.util.AnnotationValidations.validate( + KeyEventAction.class, null, mAction); + this.mDownTimeNanos = downTimeNanos; + com.android.internal.util.AnnotationValidations.validate( + SuppressLint.class, null, mDownTimeNanos, + "value", "MethodNameUnits"); + this.mFlags = flags; + this.mKeyCode = keyCode; + this.mScanCode = scanCode; + this.mMetaState = metaState; + this.mRepeatCount = repeatCount; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @android.annotation.NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public VerifiedKeyEvent[] newArray(int size) { + return new VerifiedKeyEvent[size]; + } + + @Override + public VerifiedKeyEvent createFromParcel(@android.annotation.NonNull Parcel in) { + return new VerifiedKeyEvent(in); + } + }; + + @DataClass.Generated( + time = 1581107066890L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/core/java/android/view/VerifiedKeyEvent.java", + inputSignatures = "private static final java.lang.String TAG\nprivate @android.view.VerifiedKeyEvent.KeyEventAction int mAction\nprivate @android.annotation.SuppressLint({\"MethodNameUnits\"}) long mDownTimeNanos\nprivate int mFlags\nprivate int mKeyCode\nprivate int mScanCode\nprivate int mMetaState\nprivate int mRepeatCount\npublic @android.annotation.Nullable java.lang.Boolean getFlag(int)\nclass VerifiedKeyEvent extends android.view.VerifiedInputEvent implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/view/VerifiedMotionEvent.aidl b/core/java/android/view/VerifiedMotionEvent.aidl new file mode 100644 index 000000000000..3546c631d884 --- /dev/null +++ b/core/java/android/view/VerifiedMotionEvent.aidl @@ -0,0 +1,19 @@ +/* + * 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.view; + +parcelable VerifiedMotionEvent; diff --git a/core/java/android/view/VerifiedMotionEvent.java b/core/java/android/view/VerifiedMotionEvent.java new file mode 100644 index 000000000000..b4c5d24775ea --- /dev/null +++ b/core/java/android/view/VerifiedMotionEvent.java @@ -0,0 +1,393 @@ +/* + * 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.view; + +import static android.view.MotionEvent.FLAG_WINDOW_IS_OBSCURED; +import static android.view.MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +import java.lang.annotation.Retention; + +/** + * MotionEvent that has been verified by the system. + * The data contained in this class is always a subset of a {@link MotionEvent}. Use this class to + * check which data has been confirmed by the system to be authentic. + * + * Most applications do not need to use this class. + * + * {@see android.hardware.input.InputManager#verifyInputEvent} + */ +@DataClass(genHiddenConstructor = true, genEqualsHashCode = true) +public final class VerifiedMotionEvent extends VerifiedInputEvent implements Parcelable { + private static final String TAG = "VerifiedMotionEvent"; + + /** + * The raw X coordinate of the primary pointer. + * @see MotionEvent#getRawX() + */ + private float mRawX; + + /** + * The raw Y coordinate of the primary pointer. + * @see MotionEvent#getRawY() + */ + private float mRawY; + + /** @hide */ + @Retention(SOURCE) + @IntDef({MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN, MotionEvent.ACTION_CANCEL, + MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_UP}) + public @interface MotionEventAction {}; + + /** + * The masked action being performed, without pointer index information. + * + * @see MotionEvent#getActionMasked() + */ + @MotionEventAction + private int mActionMasked; + + /** + * The time that the gesture started, in nanoseconds. + * Uses the same time base as {@link android.os.SystemClock#uptimeMillis()} + * + * @see MotionEvent#getDownTime() + */ + @SuppressLint({"MethodNameUnits"}) + private long mDownTimeNanos; + + /** + * Returns the flags for this motion event. + * + * @see MotionEvent#getFlags() + * @hide + */ + private int mFlags; + + /** + * The state of any meta / modifier keys that were in effect when the event was generated. + * + * @see MotionEvent#getMetaState() + */ + private int mMetaState; + + /** + * The state of all buttons that are pressed such as a mouse or stylus button. + * + * @see MotionEvent#getButtonState() + */ + private int mButtonState; + + /** + * Get a specific flag of this motion event, if possible. Return null if the flag value could + * not be checked. + * + * @param flag the flag of interest + * @return Boolean(true) if the motion event has the requested flag + * Boolean(false) if the motion event does not have the requested flag + * null if the flag value could not be checked + * + * @see MotionEvent#FLAG_WINDOW_IS_OBSCURED + * @see MotionEvent#FLAG_WINDOW_IS_PARTIALLY_OBSCURED + */ + public @Nullable Boolean getFlag(int flag) { + switch(flag) { + // InputDispatcher only verifies a subset of the MotionEvent flags. + // These values must be kept in sync with Input.cpp + case FLAG_WINDOW_IS_OBSCURED: + case FLAG_WINDOW_IS_PARTIALLY_OBSCURED: + return (mFlags & flag) != 0; + } + return null; + } + + // The codegen tool doesn't fully support subclasses, since it works on a per-file basis. + // To modify this file: + // 1. run codegen on this file + // 2. edit the constructor signature + // 3. add the "super" call for constructor that receives a Parcel + // 4. add the "super" call to the writeToParcel method + // 5. Update "equals" and "hashcode" methods to include VerifiedInputEvent fields + // 6. Edit "inputSignatures" to ensure MotionEventAction is properly qualified + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/VerifiedMotionEvent.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new VerifiedMotionEvent. + * + * @param rawX + * The raw X coordinate of the primary pointer. + * @param rawY + * The raw Y coordinate of the primary pointer. + * @param actionMasked + * The masked action being performed, without pointer index information. + * @param downTimeNanos + * The time that the gesture started, in nanoseconds. + * Uses the same time base as {@link android.os.SystemClock#uptimeMillis()} + * @param flags + * Returns the flags for this motion event. + * @param metaState + * The state of any meta / modifier keys that were in effect when the event was generated. + * @param buttonState + * The state of all buttons that are pressed such as a mouse or stylus button. + * @hide + */ + @DataClass.Generated.Member + public VerifiedMotionEvent( + int deviceId, long eventTimeNanos, int source, int displayId, + float rawX, + float rawY, + @MotionEventAction int actionMasked, + @SuppressLint({"MethodNameUnits"}) long downTimeNanos, + int flags, + int metaState, + int buttonState) { + super(VERIFIED_MOTION, deviceId, eventTimeNanos, source, displayId); + this.mRawX = rawX; + this.mRawY = rawY; + this.mActionMasked = actionMasked; + com.android.internal.util.AnnotationValidations.validate( + MotionEventAction.class, null, mActionMasked); + this.mDownTimeNanos = downTimeNanos; + com.android.internal.util.AnnotationValidations.validate( + SuppressLint.class, null, mDownTimeNanos, + "value", "MethodNameUnits"); + this.mFlags = flags; + this.mMetaState = metaState; + this.mButtonState = buttonState; + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The raw X coordinate of the primary pointer. + * + * @see MotionEvent#getRawX() + */ + @DataClass.Generated.Member + public float getRawX() { + return mRawX; + } + + /** + * The raw Y coordinate of the primary pointer. + * + * @see MotionEvent#getRawY() + */ + @DataClass.Generated.Member + public float getRawY() { + return mRawY; + } + + /** + * The masked action being performed, without pointer index information. + * + * @see MotionEvent#getActionMasked() + */ + @DataClass.Generated.Member + public @MotionEventAction int getActionMasked() { + return mActionMasked; + } + + /** + * The time that the gesture started, in nanoseconds. + * Uses the same time base as {@link android.os.SystemClock#uptimeMillis()} + * + * @see MotionEvent#getDownTime() + */ + @DataClass.Generated.Member + public @SuppressLint({"MethodNameUnits"}) long getDownTimeNanos() { + return mDownTimeNanos; + } + + /** + * Returns the flags for this motion event. + * + * @see MotionEvent#getFlags() + * @hide + */ + @DataClass.Generated.Member + public int getFlags() { + return mFlags; + } + + /** + * The state of any meta / modifier keys that were in effect when the event was generated. + * + * @see MotionEvent#getMetaState() + */ + @DataClass.Generated.Member + public int getMetaState() { + return mMetaState; + } + + /** + * The state of all buttons that are pressed such as a mouse or stylus button. + * + * @see MotionEvent#getButtonState() + */ + @DataClass.Generated.Member + public int getButtonState() { + return mButtonState; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(VerifiedMotionEvent other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + VerifiedMotionEvent that = (VerifiedMotionEvent) o; + //noinspection PointlessBooleanExpression + return true + && getDeviceId() == that.getDeviceId() + && getEventTimeNanos() == that.getEventTimeNanos() + && getSource() == that.getSource() + && getDisplayId() == that.getDisplayId() + && mRawX == that.mRawX + && mRawY == that.mRawY + && mActionMasked == that.mActionMasked + && mDownTimeNanos == that.mDownTimeNanos + && mFlags == that.mFlags + && mMetaState == that.mMetaState + && mButtonState == that.mButtonState; + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + getDeviceId(); + _hash = 31 * _hash + Long.hashCode(getEventTimeNanos()); + _hash = 31 * _hash + getSource(); + _hash = 31 * _hash + getDisplayId(); + _hash = 31 * _hash + Float.hashCode(mRawX); + _hash = 31 * _hash + Float.hashCode(mRawY); + _hash = 31 * _hash + mActionMasked; + _hash = 31 * _hash + Long.hashCode(mDownTimeNanos); + _hash = 31 * _hash + mFlags; + _hash = 31 * _hash + mMetaState; + _hash = 31 * _hash + mButtonState; + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@android.annotation.NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + super.writeToParcel(dest, flags); + dest.writeFloat(mRawX); + dest.writeFloat(mRawY); + dest.writeInt(mActionMasked); + dest.writeLong(mDownTimeNanos); + dest.writeInt(mFlags); + dest.writeInt(mMetaState); + dest.writeInt(mButtonState); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ VerifiedMotionEvent(@android.annotation.NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + super(in, VERIFIED_MOTION); + float rawX = in.readFloat(); + float rawY = in.readFloat(); + int actionMasked = in.readInt(); + long downTimeNanos = in.readLong(); + int flags = in.readInt(); + int metaState = in.readInt(); + int buttonState = in.readInt(); + + this.mRawX = rawX; + this.mRawY = rawY; + this.mActionMasked = actionMasked; + com.android.internal.util.AnnotationValidations.validate( + MotionEventAction.class, null, mActionMasked); + this.mDownTimeNanos = downTimeNanos; + com.android.internal.util.AnnotationValidations.validate( + SuppressLint.class, null, mDownTimeNanos, + "value", "MethodNameUnits"); + this.mFlags = flags; + this.mMetaState = metaState; + this.mButtonState = buttonState; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @android.annotation.NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public VerifiedMotionEvent[] newArray(int size) { + return new VerifiedMotionEvent[size]; + } + + @Override + public VerifiedMotionEvent createFromParcel(@android.annotation.NonNull Parcel in) { + return new VerifiedMotionEvent(in); + } + }; + + @DataClass.Generated( + time = 1581107073238L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/core/java/android/view/VerifiedMotionEvent.java", + inputSignatures = "private static final java.lang.String TAG\nprivate float mRawX\nprivate float mRawY\nprivate @android.view.VerifiedMotionEvent.MotionEventAction int mActionMasked\nprivate @android.annotation.SuppressLint({\"MethodNameUnits\"}) long mDownTimeNanos\nprivate int mFlags\nprivate int mMetaState\nprivate int mButtonState\npublic @android.annotation.Nullable java.lang.Boolean getFlag(int)\nclass VerifiedMotionEvent extends android.view.VerifiedInputEvent implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 8959d6fb845e..6ca0b0e7a9e6 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -125,6 +125,8 @@ cc_library_shared { "android_view_SurfaceSession.cpp", "android_view_TextureView.cpp", "android_view_VelocityTracker.cpp", + "android_view_VerifiedKeyEvent.cpp", + "android_view_VerifiedMotionEvent.cpp", "android_text_Hyphenator.cpp", "android_os_Debug.cpp", "android_os_GraphicsEnvironment.cpp", diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp index 57979bd9b546..bbe563e12a4c 100644 --- a/core/jni/android_view_KeyEvent.cpp +++ b/core/jni/android_view_KeyEvent.cpp @@ -102,7 +102,7 @@ jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) { event->getRepeatCount(), event->getMetaState(), event->getDeviceId(), event->getScanCode(), event->getFlags(), event->getSource(), - event->getDisplayId(), hmac.get(), NULL); + event->getDisplayId(), hmac.get(), nullptr); if (env->ExceptionCheck()) { ALOGE("An exception occurred while obtaining a key event."); LOGE_EX(env); diff --git a/core/jni/android_view_VerifiedKeyEvent.cpp b/core/jni/android_view_VerifiedKeyEvent.cpp new file mode 100644 index 000000000000..8fc301ccc735 --- /dev/null +++ b/core/jni/android_view_VerifiedKeyEvent.cpp @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#define LOG_TAG "MotionEvent-JNI" + +#include "android_view_VerifiedKeyEvent.h" +#include +#include "core_jni_helpers.h" + +namespace android { + +// ---------------------------------------------------------------------------- + +jobject android_view_VerifiedKeyEvent(JNIEnv* env, const VerifiedKeyEvent& event) { + static jclass clazz = FindClassOrDie(env, "android/view/VerifiedKeyEvent"); + + static jmethodID constructor = GetMethodIDOrDie(env, clazz, "", "(IJIIIJIIIII)V"); + + jobject object = + env->NewObject(clazz, constructor, event.deviceId, event.eventTimeNanos, event.source, + event.displayId, event.action, event.downTimeNanos, event.flags, + event.keyCode, event.scanCode, event.metaState, event.repeatCount); + return object; +} + +} // namespace android diff --git a/core/jni/android_view_VerifiedKeyEvent.h b/core/jni/android_view_VerifiedKeyEvent.h new file mode 100644 index 000000000000..032291b3c39f --- /dev/null +++ b/core/jni/android_view_VerifiedKeyEvent.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef _ANDROID_VIEW_VERIFIEDKEYEVENT_H +#define _ANDROID_VIEW_VERIFIEDKEYEVENT_H + +#include "jni.h" + +namespace android { + +class VerifiedKeyEvent; + +/* Create an instance of a DVM VerifiedMotionEvent object + * Return nullptr on error. */ +extern jobject android_view_VerifiedKeyEvent(JNIEnv* env, const VerifiedKeyEvent& event); + +} // namespace android + +#endif // _ANDROID_VIEW_VERIFIEDKEYEVENT_H diff --git a/core/jni/android_view_VerifiedMotionEvent.cpp b/core/jni/android_view_VerifiedMotionEvent.cpp new file mode 100644 index 000000000000..7a5c71aa6602 --- /dev/null +++ b/core/jni/android_view_VerifiedMotionEvent.cpp @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#define LOG_TAG "MotionEvent-JNI" + +#include "android_view_VerifiedMotionEvent.h" +#include +#include "core_jni_helpers.h" + +namespace android { + +// ---------------------------------------------------------------------------- + +jobject android_view_VerifiedMotionEvent(JNIEnv* env, const VerifiedMotionEvent& event) { + static jclass clazz = FindClassOrDie(env, "android/view/VerifiedMotionEvent"); + + static jmethodID constructor = GetMethodIDOrDie(env, clazz, "", "(IJIIFFIJIII)V"); + + jobject object = + env->NewObject(clazz, constructor, event.deviceId, event.eventTimeNanos, event.source, + event.displayId, event.rawX, event.rawY, event.actionMasked, + event.downTimeNanos, event.flags, event.metaState, event.buttonState); + return object; +} + +} // namespace android diff --git a/core/jni/android_view_VerifiedMotionEvent.h b/core/jni/android_view_VerifiedMotionEvent.h new file mode 100644 index 000000000000..deda1b7255da --- /dev/null +++ b/core/jni/android_view_VerifiedMotionEvent.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef _ANDROID_VIEW_VERIFIEDMOTIONEVENT_H +#define _ANDROID_VIEW_VERIFIEDMOTIONEVENT_H + +#include "jni.h" + +namespace android { + +class VerifiedMotionEvent; + +/* Create an instance of a DVM VerifiedMotionEvent object + * Return nullptr on error. */ +extern jobject android_view_VerifiedMotionEvent(JNIEnv* env, const VerifiedMotionEvent& event); + +} // namespace android + +#endif // _ANDROID_VIEW_VERIFIEDMOTIONEVENT_H diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index e04d3de622d8..18778b93fb57 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -3,6 +3,7 @@ android_test { srcs: [ "src/**/*.java", + "src/**/*.kt", "src/**/I*.aidl", "DisabledTestApp/src/**/*.java", "EnabledTestApp/src/**/*.java", diff --git a/core/tests/coretests/src/android/view/VerifiedKeyEventTest.kt b/core/tests/coretests/src/android/view/VerifiedKeyEventTest.kt new file mode 100644 index 000000000000..531d55d7738a --- /dev/null +++ b/core/tests/coretests/src/android/view/VerifiedKeyEventTest.kt @@ -0,0 +1,165 @@ +/* + * 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.view + +import android.view.InputDevice.SOURCE_KEYBOARD +import android.view.KeyEvent.ACTION_DOWN +import android.os.Parcel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.runner.RunWith +import org.junit.Test + +@RunWith(AndroidJUnit4::class) +@SmallTest +class VerifiedKeyEventTest { + + @Test + fun testConstructor() { + val event = createVerifiedKeyEvent() + + assertEquals(DEVICE_ID, event.deviceId) + assertEquals(EVENT_TIME_NANOS, event.eventTimeNanos) + assertEquals(SOURCE, event.source) + assertEquals(DISPLAY_ID, event.displayId) + + assertEquals(ACTION, event.action) + assertEquals(DOWN_TIME_NANOS, event.downTimeNanos) + assertEquals(FLAGS, event.flags) + assertEquals(KEY_CODE, event.keyCode) + assertEquals(SCAN_CODE, event.scanCode) + assertEquals(META_STATE, event.metaState) + assertEquals(REPEAT_COUNT, event.repeatCount) + } + + /** + * Write to parcel as a KeyEvent, read back as a KeyEvent + */ + @Test + fun testParcelUnparcel() { + val keyEvent = createVerifiedKeyEvent() + val parcel = Parcel.obtain() + keyEvent.writeToParcel(parcel, 0 /*flags*/) + parcel.setDataPosition(0) + + val unparceledKeyEvent = VerifiedKeyEvent.CREATOR.createFromParcel(parcel) + parcel.recycle() + + compareVerifiedKeyEvents(keyEvent, unparceledKeyEvent) + } + + /** + * Write to parcel as an InputEvent, read back as an InputEvent + */ + @Test + fun testParcelInputEvent() { + val keyEvent = createVerifiedKeyEvent() + val inputEvent: VerifiedInputEvent = keyEvent + val parcel = Parcel.obtain() + inputEvent.writeToParcel(parcel, 0 /*flags*/) + parcel.setDataPosition(0) + + val unparceledEvent = VerifiedInputEvent.CREATOR.createFromParcel(parcel) + parcel.recycle() + + assertTrue(unparceledEvent is VerifiedKeyEvent) + compareVerifiedKeyEvents(keyEvent, unparceledEvent as VerifiedKeyEvent) + } + + /** + * Write to parcel as a KeyEvent, read back as an InputEvent + */ + @Test + fun testParcelKeyEvent() { + val keyEvent = createVerifiedKeyEvent() + val parcel = Parcel.obtain() + keyEvent.writeToParcel(parcel, 0 /*flags*/) + parcel.setDataPosition(0) + + val unparceledEvent = VerifiedInputEvent.CREATOR.createFromParcel(parcel) + parcel.recycle() + + assertTrue(unparceledEvent is VerifiedKeyEvent) + compareVerifiedKeyEvents(keyEvent, unparceledEvent as VerifiedKeyEvent) + } + + /** + * Write to parcel as an InputEvent, read back as a KeyEvent + */ + @Test + fun testParcelInputToKeyEvent() { + val keyEvent = createVerifiedKeyEvent() + val inputEvent: VerifiedInputEvent = keyEvent + val parcel = Parcel.obtain() + inputEvent.writeToParcel(parcel, 0 /*flags*/) + parcel.setDataPosition(0) + + val unparceledEvent = VerifiedKeyEvent.CREATOR.createFromParcel(parcel) + parcel.recycle() + + compareVerifiedKeyEvents(keyEvent, unparceledEvent) + } + + @Test + fun testEqualsHashcode() { + val keyEvent1 = createVerifiedKeyEvent() + val keyEvent2 = createVerifiedKeyEvent() + compareVerifiedKeyEvents(keyEvent1, keyEvent2) + } + + companion object { + private const val DEVICE_ID = 0 + private const val EVENT_TIME_NANOS: Long = 2000 + private const val SOURCE = SOURCE_KEYBOARD + private const val DISPLAY_ID = 2 + + private const val ACTION = ACTION_DOWN + private const val DOWN_TIME_NANOS: Long = 1000 + private const val FLAGS = 3 + private const val KEY_CODE = 4 + private const val SCAN_CODE = 5 + private const val META_STATE = 11 + private const val REPEAT_COUNT = 22 + + private fun createVerifiedKeyEvent(): VerifiedKeyEvent { + return VerifiedKeyEvent(DEVICE_ID, EVENT_TIME_NANOS, SOURCE, DISPLAY_ID, ACTION, + DOWN_TIME_NANOS, FLAGS, KEY_CODE, SCAN_CODE, META_STATE, REPEAT_COUNT) + } + + private fun compareVerifiedKeyEvents(event1: VerifiedKeyEvent, event2: VerifiedKeyEvent) { + assertEquals(event1, event2) + assertEquals(event1.hashCode(), event2.hashCode()) + + assertEquals(event1.deviceId, event2.deviceId) + assertEquals(event1.eventTimeNanos, event2.eventTimeNanos) + assertEquals(event1.source, event2.source) + assertEquals(event1.displayId, event2.displayId) + + assertEquals(event1.action, event2.action) + assertEquals(event1.downTimeNanos, event2.downTimeNanos) + assertEquals(event1.flags, event2.flags) + assertEquals(event1.keyCode, event2.keyCode) + assertEquals(event1.scanCode, event2.scanCode) + assertEquals(event1.metaState, event2.metaState) + assertEquals(event1.repeatCount, event2.repeatCount) + } + } +} diff --git a/core/tests/coretests/src/android/view/VerifiedMotionEventTest.kt b/core/tests/coretests/src/android/view/VerifiedMotionEventTest.kt new file mode 100644 index 000000000000..2c4851f0ab4e --- /dev/null +++ b/core/tests/coretests/src/android/view/VerifiedMotionEventTest.kt @@ -0,0 +1,185 @@ +/* + * 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.view + +import android.view.InputDevice.SOURCE_TOUCHSCREEN +import android.view.MotionEvent.ACTION_MOVE +import android.view.MotionEvent.FLAG_WINDOW_IS_OBSCURED +import android.view.MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED +import android.view.MotionEvent.FLAG_TAINTED +import android.os.Parcel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.runner.RunWith +import org.junit.Test + +@RunWith(AndroidJUnit4::class) +@SmallTest +class VerifiedMotionEventTest { + + @Test + fun testConstructor() { + val event = createVerifiedMotionEvent() + + assertEquals(DEVICE_ID, event.deviceId) + assertEquals(EVENT_TIME_NANOS, event.eventTimeNanos) + assertEquals(SOURCE, event.source) + assertEquals(DISPLAY_ID, event.displayId) + + assertEquals(RAW_X, event.rawX, 0f) + assertEquals(RAW_Y, event.rawY, 0f) + assertEquals(ACTION_MASKED, event.actionMasked) + assertEquals(DOWN_TIME_NANOS, event.downTimeNanos) + assertEquals(META_STATE, event.metaState) + assertEquals(BUTTON_STATE, event.buttonState) + } + + /** + * Write to parcel as a MotionEvent, read back as a MotionEvent + */ + @Test + fun testParcelUnparcel() { + val motionEvent = createVerifiedMotionEvent() + val parcel = Parcel.obtain() + motionEvent.writeToParcel(parcel, 0 /*flags*/) + parcel.setDataPosition(0) + + val unparceledMotionEvent = VerifiedMotionEvent.CREATOR.createFromParcel(parcel) + parcel.recycle() + + compareVerifiedMotionEvents(motionEvent, unparceledMotionEvent) + } + + /** + * Write to parcel as an InputEvent, read back as an InputEvent + */ + @Test + fun testParcelInputEvent() { + val motionEvent = createVerifiedMotionEvent() + val inputEvent: VerifiedInputEvent = motionEvent + val parcel = Parcel.obtain() + inputEvent.writeToParcel(parcel, 0 /*flags*/) + parcel.setDataPosition(0) + + val unparceledEvent = VerifiedInputEvent.CREATOR.createFromParcel(parcel) + parcel.recycle() + + assertTrue(unparceledEvent is VerifiedMotionEvent) + compareVerifiedMotionEvents(motionEvent, unparceledEvent as VerifiedMotionEvent) + } + + /** + * Write to parcel as a MotionEvent, read back as an InputEvent + */ + @Test + fun testParcelMotionEvent() { + val motionEvent = createVerifiedMotionEvent() + val parcel = Parcel.obtain() + motionEvent.writeToParcel(parcel, 0 /*flags*/) + parcel.setDataPosition(0) + + val unparceledEvent = VerifiedInputEvent.CREATOR.createFromParcel(parcel) + parcel.recycle() + + assertTrue(unparceledEvent is VerifiedMotionEvent) + compareVerifiedMotionEvents(motionEvent, unparceledEvent as VerifiedMotionEvent) + } + + /** + * Write to parcel as an InputEvent, read back as a MotionEvent + */ + @Test + fun testParcelInputToMotionEvent() { + val motionEvent = createVerifiedMotionEvent() + val inputEvent: VerifiedInputEvent = motionEvent + val parcel = Parcel.obtain() + inputEvent.writeToParcel(parcel, 0 /*flags*/) + parcel.setDataPosition(0) + + val unparceledEvent = VerifiedMotionEvent.CREATOR.createFromParcel(parcel) + parcel.recycle() + + compareVerifiedMotionEvents(motionEvent, unparceledEvent) + } + + @Test + fun testGetFlag() { + val motionEvent = createVerifiedMotionEvent() + // Invalid value of a flag + assertNull(motionEvent.getFlag(0)) + // Flag that was not set + assertEquals(false, motionEvent.getFlag(FLAG_WINDOW_IS_PARTIALLY_OBSCURED)) + // Flag that was set + assertEquals(true, motionEvent.getFlag(FLAG_WINDOW_IS_OBSCURED)) + // Only 1 flag at a time is accepted + assertNull(motionEvent.getFlag( + FLAG_WINDOW_IS_PARTIALLY_OBSCURED or FLAG_WINDOW_IS_OBSCURED)) + // Flag that is not verified returns null + assertNull(motionEvent.getFlag(FLAG_TAINTED)) + } + + @Test + fun testEqualsHashcode() { + val motionEvent1 = createVerifiedMotionEvent() + val motionEvent2 = createVerifiedMotionEvent() + compareVerifiedMotionEvents(motionEvent1, motionEvent2) + } + + companion object { + private const val DEVICE_ID = 0 + private const val EVENT_TIME_NANOS: Long = 2000 + private const val SOURCE = SOURCE_TOUCHSCREEN + private const val DISPLAY_ID = 2 + private const val RAW_X = 100f + private const val RAW_Y = 200f + private const val ACTION_MASKED = ACTION_MOVE + private const val DOWN_TIME_NANOS: Long = 1000 + private const val FLAGS = FLAG_WINDOW_IS_OBSCURED + private const val META_STATE = 11 + private const val BUTTON_STATE = 22 + + private fun createVerifiedMotionEvent(): VerifiedMotionEvent { + return VerifiedMotionEvent(DEVICE_ID, EVENT_TIME_NANOS, SOURCE, DISPLAY_ID, + RAW_X, RAW_Y, ACTION_MASKED, DOWN_TIME_NANOS, FLAGS, META_STATE, BUTTON_STATE) + } + + private fun compareVerifiedMotionEvents( + event1: VerifiedMotionEvent, + event2: VerifiedMotionEvent + ) { + assertEquals(event1, event2) + assertEquals(event1.hashCode(), event2.hashCode()) + + assertEquals(event1.deviceId, event2.deviceId) + assertEquals(event1.eventTimeNanos, event2.eventTimeNanos) + assertEquals(event1.source, event2.source) + assertEquals(event1.displayId, event2.displayId) + + assertEquals(event1.rawX, event2.rawX, 0f) + assertEquals(event1.rawY, event2.rawY, 0f) + assertEquals(event1.actionMasked, event2.actionMasked) + assertEquals(event1.downTimeNanos, event2.downTimeNanos) + assertEquals(event1.metaState, event2.metaState) + assertEquals(event1.buttonState, event2.buttonState) + } + } +} diff --git a/native/android/Android.bp b/native/android/Android.bp index 0c6f507787d9..257ae7332cc1 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -25,6 +25,7 @@ cc_defaults { cflags: [ "-Wall", "-Werror", + "-Wextra", "-Wunused", "-Wunreachable-code", ], diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index a8f706cdd629..ca06b47a6e80 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -79,6 +79,7 @@ import android.view.InputWindowHandle; import android.view.KeyEvent; import android.view.PointerIcon; import android.view.Surface; +import android.view.VerifiedInputEvent; import android.view.ViewConfiguration; import android.widget.Toast; @@ -214,6 +215,7 @@ public class InputManagerService extends IInputManager.Stub private static native int nativeInjectInputEvent(long ptr, InputEvent event, int injectorPid, int injectorUid, int syncMode, int timeoutMillis, int policyFlags); + private static native VerifiedInputEvent nativeVerifyInputEvent(long ptr, InputEvent event); private static native void nativeToggleCapsLock(long ptr, int deviceId); private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles, int displayId); @@ -672,6 +674,11 @@ public class InputManagerService extends IInputManager.Stub } } + @Override // Binder call + public VerifiedInputEvent verifyInputEvent(InputEvent event) { + return nativeVerifyInputEvent(mPtr, event); + } + /** * Gets information about the input device with the specified id. * @param deviceId The device id. diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 49db3d5b2b64..8772edd73845 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -50,13 +50,15 @@ #include +#include #include +#include #include #include #include -#include #include -#include +#include +#include #include #include @@ -1513,6 +1515,49 @@ static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */, } } +static jobject nativeVerifyInputEvent(JNIEnv* env, jclass /* clazz */, jlong ptr, + jobject inputEventObj) { + NativeInputManager* im = reinterpret_cast(ptr); + + if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) { + KeyEvent keyEvent; + status_t status = android_view_KeyEvent_toNative(env, inputEventObj, &keyEvent); + if (status) { + jniThrowRuntimeException(env, "Could not read contents of KeyEvent object."); + return nullptr; + } + + std::unique_ptr verifiedEvent = + im->getInputManager()->getDispatcher()->verifyInputEvent(keyEvent); + if (verifiedEvent == nullptr) { + return nullptr; + } + + return android_view_VerifiedKeyEvent(env, + static_cast(*verifiedEvent)); + } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) { + const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj); + if (!motionEvent) { + jniThrowRuntimeException(env, "Could not read contents of MotionEvent object."); + return nullptr; + } + + std::unique_ptr verifiedEvent = + im->getInputManager()->getDispatcher()->verifyInputEvent(*motionEvent); + + if (verifiedEvent == nullptr) { + return nullptr; + } + + return android_view_VerifiedMotionEvent(env, + static_cast( + *verifiedEvent)); + } else { + jniThrowRuntimeException(env, "Invalid input event type."); + return nullptr; + } +} + static void nativeToggleCapsLock(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId) { NativeInputManager* im = reinterpret_cast(ptr); @@ -1735,90 +1780,61 @@ static void nativeNotifyPortAssociationsChanged(JNIEnv* env, jclass /* clazz */, // ---------------------------------------------------------------------------- static const JNINativeMethod gInputManagerMethods[] = { - /* name, signature, funcPtr */ - { "nativeInit", - "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)J", - (void*) nativeInit }, - { "nativeStart", "(J)V", - (void*) nativeStart }, - { "nativeSetDisplayViewports", "(J[Landroid/hardware/display/DisplayViewport;)V", - (void*) nativeSetDisplayViewports }, - { "nativeGetScanCodeState", "(JIII)I", - (void*) nativeGetScanCodeState }, - { "nativeGetKeyCodeState", "(JIII)I", - (void*) nativeGetKeyCodeState }, - { "nativeGetSwitchState", "(JIII)I", - (void*) nativeGetSwitchState }, - { "nativeHasKeys", "(JII[I[Z)Z", - (void*) nativeHasKeys }, - { "nativeRegisterInputChannel", - "(JLandroid/view/InputChannel;)V", - (void*) nativeRegisterInputChannel }, - { "nativeRegisterInputMonitor", - "(JLandroid/view/InputChannel;IZ)V", - (void*) nativeRegisterInputMonitor}, - { "nativeUnregisterInputChannel", "(JLandroid/view/InputChannel;)V", - (void*) nativeUnregisterInputChannel }, - { "nativePilferPointers", "(JLandroid/os/IBinder;)V", - (void*) nativePilferPointers }, - { "nativeSetInputFilterEnabled", "(JZ)V", - (void*) nativeSetInputFilterEnabled }, - { "nativeSetInTouchMode", "(JZ)V", - (void*) nativeSetInTouchMode }, - { "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIII)I", - (void*) nativeInjectInputEvent }, - { "nativeToggleCapsLock", "(JI)V", - (void*) nativeToggleCapsLock }, - { "nativeSetInputWindows", "(J[Landroid/view/InputWindowHandle;I)V", - (void*) nativeSetInputWindows }, - { "nativeSetFocusedApplication", "(JILandroid/view/InputApplicationHandle;)V", - (void*) nativeSetFocusedApplication }, - { "nativeSetFocusedDisplay", "(JI)V", - (void*) nativeSetFocusedDisplay }, - { "nativeSetPointerCapture", "(JZ)V", - (void*) nativeSetPointerCapture }, - { "nativeSetInputDispatchMode", "(JZZ)V", - (void*) nativeSetInputDispatchMode }, - { "nativeSetSystemUiVisibility", "(JI)V", - (void*) nativeSetSystemUiVisibility }, - { "nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)Z", - (void*) nativeTransferTouchFocus }, - { "nativeSetPointerSpeed", "(JI)V", - (void*) nativeSetPointerSpeed }, - { "nativeSetShowTouches", "(JZ)V", - (void*) nativeSetShowTouches }, - { "nativeSetInteractive", "(JZ)V", - (void*) nativeSetInteractive }, - { "nativeReloadCalibration", "(J)V", - (void*) nativeReloadCalibration }, - { "nativeVibrate", "(JI[JII)V", - (void*) nativeVibrate }, - { "nativeCancelVibrate", "(JII)V", - (void*) nativeCancelVibrate }, - { "nativeReloadKeyboardLayouts", "(J)V", - (void*) nativeReloadKeyboardLayouts }, - { "nativeReloadDeviceAliases", "(J)V", - (void*) nativeReloadDeviceAliases }, - { "nativeDump", "(J)Ljava/lang/String;", - (void*) nativeDump }, - { "nativeMonitor", "(J)V", - (void*) nativeMonitor }, - { "nativeIsInputDeviceEnabled", "(JI)Z", - (void*) nativeIsInputDeviceEnabled }, - { "nativeEnableInputDevice", "(JI)V", - (void*) nativeEnableInputDevice }, - { "nativeDisableInputDevice", "(JI)V", - (void*) nativeDisableInputDevice }, - { "nativeSetPointerIconType", "(JI)V", - (void*) nativeSetPointerIconType }, - { "nativeReloadPointerIcons", "(J)V", - (void*) nativeReloadPointerIcons }, - { "nativeSetCustomPointerIcon", "(JLandroid/view/PointerIcon;)V", - (void*) nativeSetCustomPointerIcon }, - { "nativeCanDispatchToDisplay", "(JII)Z", - (void*) nativeCanDispatchToDisplay }, - { "nativeNotifyPortAssociationsChanged", "(J)V", - (void*) nativeNotifyPortAssociationsChanged }, + /* name, signature, funcPtr */ + {"nativeInit", + "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/" + "MessageQueue;)J", + (void*)nativeInit}, + {"nativeStart", "(J)V", (void*)nativeStart}, + {"nativeSetDisplayViewports", "(J[Landroid/hardware/display/DisplayViewport;)V", + (void*)nativeSetDisplayViewports}, + {"nativeGetScanCodeState", "(JIII)I", (void*)nativeGetScanCodeState}, + {"nativeGetKeyCodeState", "(JIII)I", (void*)nativeGetKeyCodeState}, + {"nativeGetSwitchState", "(JIII)I", (void*)nativeGetSwitchState}, + {"nativeHasKeys", "(JII[I[Z)Z", (void*)nativeHasKeys}, + {"nativeRegisterInputChannel", "(JLandroid/view/InputChannel;)V", + (void*)nativeRegisterInputChannel}, + {"nativeRegisterInputMonitor", "(JLandroid/view/InputChannel;IZ)V", + (void*)nativeRegisterInputMonitor}, + {"nativeUnregisterInputChannel", "(JLandroid/view/InputChannel;)V", + (void*)nativeUnregisterInputChannel}, + {"nativePilferPointers", "(JLandroid/os/IBinder;)V", (void*)nativePilferPointers}, + {"nativeSetInputFilterEnabled", "(JZ)V", (void*)nativeSetInputFilterEnabled}, + {"nativeSetInTouchMode", "(JZ)V", (void*)nativeSetInTouchMode}, + {"nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIII)I", + (void*)nativeInjectInputEvent}, + {"nativeVerifyInputEvent", "(JLandroid/view/InputEvent;)Landroid/view/VerifiedInputEvent;", + (void*)nativeVerifyInputEvent}, + {"nativeToggleCapsLock", "(JI)V", (void*)nativeToggleCapsLock}, + {"nativeSetInputWindows", "(J[Landroid/view/InputWindowHandle;I)V", + (void*)nativeSetInputWindows}, + {"nativeSetFocusedApplication", "(JILandroid/view/InputApplicationHandle;)V", + (void*)nativeSetFocusedApplication}, + {"nativeSetFocusedDisplay", "(JI)V", (void*)nativeSetFocusedDisplay}, + {"nativeSetPointerCapture", "(JZ)V", (void*)nativeSetPointerCapture}, + {"nativeSetInputDispatchMode", "(JZZ)V", (void*)nativeSetInputDispatchMode}, + {"nativeSetSystemUiVisibility", "(JI)V", (void*)nativeSetSystemUiVisibility}, + {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)Z", + (void*)nativeTransferTouchFocus}, + {"nativeSetPointerSpeed", "(JI)V", (void*)nativeSetPointerSpeed}, + {"nativeSetShowTouches", "(JZ)V", (void*)nativeSetShowTouches}, + {"nativeSetInteractive", "(JZ)V", (void*)nativeSetInteractive}, + {"nativeReloadCalibration", "(J)V", (void*)nativeReloadCalibration}, + {"nativeVibrate", "(JI[JII)V", (void*)nativeVibrate}, + {"nativeCancelVibrate", "(JII)V", (void*)nativeCancelVibrate}, + {"nativeReloadKeyboardLayouts", "(J)V", (void*)nativeReloadKeyboardLayouts}, + {"nativeReloadDeviceAliases", "(J)V", (void*)nativeReloadDeviceAliases}, + {"nativeDump", "(J)Ljava/lang/String;", (void*)nativeDump}, + {"nativeMonitor", "(J)V", (void*)nativeMonitor}, + {"nativeIsInputDeviceEnabled", "(JI)Z", (void*)nativeIsInputDeviceEnabled}, + {"nativeEnableInputDevice", "(JI)V", (void*)nativeEnableInputDevice}, + {"nativeDisableInputDevice", "(JI)V", (void*)nativeDisableInputDevice}, + {"nativeSetPointerIconType", "(JI)V", (void*)nativeSetPointerIconType}, + {"nativeReloadPointerIcons", "(J)V", (void*)nativeReloadPointerIcons}, + {"nativeSetCustomPointerIcon", "(JLandroid/view/PointerIcon;)V", + (void*)nativeSetCustomPointerIcon}, + {"nativeCanDispatchToDisplay", "(JII)Z", (void*)nativeCanDispatchToDisplay}, + {"nativeNotifyPortAssociationsChanged", "(J)V", (void*)nativeNotifyPortAssociationsChanged}, }; #define FIND_CLASS(var, className) \ -- cgit v1.2.3-59-g8ed1b From dd7bf2fea566be919c7807b14833c3d3c1fa8458 Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Fri, 31 Jan 2020 18:50:02 -0800 Subject: Add compatibility param to setFrameRate() api Add a compatiblity param to the setFrameRate() api, so the system has more info to decide the device frame rate when there are multiple competing preferences. I also changed the plumbing for setFrameRate() to go directly to surface flinger, instead of through buffer queue. We're trying to avoid changes to buffer queue code, to avoid disturbing the prebuilts. Bug: 137287430 Test: Added new cts tests to verify behavior of the compatibility param. cts-tradefed run commandAndExit cts-dev --module CtsGraphicsTestCases --test android.graphics.cts.SetFrameRateTest Test: /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test --gtest_filter='SetFrameRateTest.*' Change-Id: I9123afee2ba63d01ff35fb2b257a1ee0e4928ddd --- api/current.txt | 6 ++-- core/java/android/view/Surface.java | 47 ++++++++++++++++++++++++++---- core/java/android/view/SurfaceControl.java | 12 +++++--- core/jni/android_view_Surface.cpp | 11 +++++-- core/jni/android_view_SurfaceControl.cpp | 9 ++++-- native/android/surface_control.cpp | 13 +++------ 6 files changed, 72 insertions(+), 26 deletions(-) (limited to 'native/android') diff --git a/api/current.txt b/api/current.txt index 7bfd9a403ae9..66824988ce47 100644 --- a/api/current.txt +++ b/api/current.txt @@ -53250,11 +53250,13 @@ package android.view { method public android.graphics.Canvas lockHardwareCanvas(); method public void readFromParcel(android.os.Parcel); method public void release(); - method public void setFrameRate(@FloatRange(from=0.0) float); + method public void setFrameRate(@FloatRange(from=0.0) float, int); method @Deprecated public void unlockCanvas(android.graphics.Canvas); method public void unlockCanvasAndPost(android.graphics.Canvas); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; // 0x0 + field public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; // 0x1 field public static final int ROTATION_0 = 0; // 0x0 field public static final int ROTATION_180 = 2; // 0x2 field public static final int ROTATION_270 = 3; // 0x3 @@ -53294,7 +53296,7 @@ package android.view { method @NonNull public android.view.SurfaceControl.Transaction reparent(@NonNull android.view.SurfaceControl, @Nullable android.view.SurfaceControl); method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float); method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int); - method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float); + method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int); method @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int); method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int); method @NonNull public android.view.SurfaceControl.Transaction setVisibility(@NonNull android.view.SurfaceControl, boolean); diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 4ac6a666a21b..13d6dd67bb19 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -16,6 +16,8 @@ package android.view; +import static android.system.OsConstants.EINVAL; + import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.NonNull; @@ -89,7 +91,8 @@ public class Surface implements Parcelable { private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled); private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled); - private static native int nativeSetFrameRate(long nativeObject, float frameRate); + private static native int nativeSetFrameRate( + long nativeObject, float frameRate, int compatibility); public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -184,6 +187,28 @@ public class Surface implements Parcelable { */ public static final int ROTATION_270 = 3; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"FRAME_RATE_COMPATIBILITY_"}, + value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE}) + public @interface FrameRateCompatibility {} + + // From native_window.h. Keep these in sync. + /** + * There are no inherent restrictions on the frame rate of this surface. + */ + public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; + + /** + * This surface is being used to display content with an inherently fixed frame rate, + * e.g. a video that has a specific frame rate. When the system selects a frame rate + * other than what the app requested, the app will need to do pull down or use some + * other technique to adapt to the system's frame rate. The user experience is likely + * to be worse (e.g. more frame stuttering) than it would be if the system had chosen + * the app's requested frame rate. + */ + public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; + /** * Create an empty surface, which will later be filled in by readFromParcel(). * @hide @@ -864,11 +889,23 @@ public class Surface implements Parcelable { * called. The frameRate param does *not* need to be a valid refresh rate for this * device's display - e.g., it's fine to pass 30fps to a device that can only run the * display at 60fps. + * + * @param compatibility The frame rate compatibility of this surface. The + * compatibility value may influence the system's choice of display frame rate. See + * the FRAME_RATE_COMPATIBILITY_* values for more info. + * + * @throws IllegalArgumentException If frameRate or compatibility are invalid. */ - public void setFrameRate(@FloatRange(from = 0.0) float frameRate) { - int error = nativeSetFrameRate(mNativeObject, frameRate); - if (error != 0) { - throw new RuntimeException("Failed to set frame rate on Surface"); + public void setFrameRate( + @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) { + synchronized (mLock) { + checkNotReleasedLocked(); + int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility); + if (error == -EINVAL) { + throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()"); + } else if (error != 0) { + throw new RuntimeException("Failed to set frame rate on Surface"); + } } } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index cf48c52825e9..6c2c143e51ba 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -213,7 +213,7 @@ public final class SurfaceControl implements Parcelable { @Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius); private static native void nativeSetFrameRate( - long transactionObj, long nativeObject, float frameRate); + long transactionObj, long nativeObject, float frameRate, int compatibility); private final CloseGuard mCloseGuard = CloseGuard.get(); private String mName; @@ -2735,13 +2735,17 @@ public final class SurfaceControl implements Parcelable { * isn't called. The frameRate param does *not* need to be a valid refresh * rate for this device's display - e.g., it's fine to pass 30fps to a * device that can only run the display at 60fps. + * @param compatibility The frame rate compatibility of this surface. The compatibility + * value may influence the system's choice of display frame rate. See + * the Surface.FRAME_RATE_COMPATIBILITY_* values for more info. * @return This transaction object. */ @NonNull - public Transaction setFrameRate( - @NonNull SurfaceControl sc, @FloatRange(from = 0.0) float frameRate) { + public Transaction setFrameRate(@NonNull SurfaceControl sc, + @FloatRange(from = 0.0) float frameRate, + @Surface.FrameRateCompatibility int compatibility) { checkPreconditions(sc); - nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate); + nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate, compatibility); return this; } diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index b01083bba643..8a53bd0db8af 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -413,10 +413,15 @@ static jint nativeSetAutoRefreshEnabled(JNIEnv* env, jclass clazz, jlong nativeO return anw->perform(surface, NATIVE_WINDOW_SET_AUTO_REFRESH, int(enabled)); } -static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate) { +static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate, + jint compatibility) { Surface* surface = reinterpret_cast(nativeObject); ANativeWindow* anw = static_cast(surface); - return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, float(frameRate)); + // Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and + // NATIVE_WINDOW_SET_FRAME_RATE takes an + // ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The values are identical + // though, so no need to explicitly convert. + return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, float(frameRate), compatibility); } // ---------------------------------------------------------------------------- @@ -453,7 +458,7 @@ static const JNINativeMethod gSurfaceMethods[] = { (void*)nativeAttachAndQueueBufferWithColorSpace}, {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled}, {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled}, - {"nativeSetFrameRate", "(JF)I", (void*)nativeSetFrameRate}, + {"nativeSetFrameRate", "(JFI)I", (void*)nativeSetFrameRate}, }; int register_android_view_Surface(JNIEnv* env) diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index ce9a048f8006..e6bcd251ce02 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -593,11 +593,14 @@ static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionOb } static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject, - jfloat frameRate) { + jfloat frameRate, jint compatibility) { auto transaction = reinterpret_cast(transactionObj); const auto ctrl = reinterpret_cast(nativeObject); - transaction->setFrameRate(ctrl, frameRate); + // Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and + // Transaction::setFrameRate() takes an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The + // values are identical though, so no need to convert anything. + transaction->setFrameRate(ctrl, frameRate, static_cast(compatibility)); } static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) { @@ -1410,7 +1413,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetLayerStack }, {"nativeSetShadowRadius", "(JJF)V", (void*)nativeSetShadowRadius }, - {"nativeSetFrameRate", "(JJF)V", + {"nativeSetFrameRate", "(JJFI)V", (void*)nativeSetFrameRate }, {"nativeGetPhysicalDisplayIds", "()[J", (void*)nativeGetPhysicalDisplayIds }, diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index ba793e83f1fb..0af6cbf3cb40 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -547,16 +547,11 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction, } void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* aSurfaceTransaction, - ASurfaceControl* aSurfaceControl, float frameRate) { + ASurfaceControl* aSurfaceControl, float frameRate, + int8_t compatibility) { CHECK_NOT_NULL(aSurfaceTransaction); CHECK_NOT_NULL(aSurfaceControl); - - sp surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); - if (frameRate < 0) { - ALOGE("Failed to set frame ate - invalid frame rate"); - return; - } - Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); - transaction->setFrameRate(surfaceControl, frameRate); + sp surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + transaction->setFrameRate(surfaceControl, frameRate, compatibility); } -- cgit v1.2.3-59-g8ed1b From 48dbcaae414f71da46064b907aaa635d9417653e Mon Sep 17 00:00:00 2001 From: Chris Ye Date: Mon, 10 Feb 2020 13:29:01 -0800 Subject: Add native Thermal Throttling API to libandroid. Add native thermal manager API of thermal mananger service into libandroid. Export Thermal API as NDK library. Bug: 137151587 Bug: 136285293 Test: build, atest thermalmanager-test atest CtsThermalTestCases Change-Id: Ia49fb2133624ffcd6168af804ae612ef2bb190f2 --- Android.bp | 12 + core/java/android/os/CoolingDevice.aidl | 2 +- core/java/android/os/IThermalService.aidl | 9 +- core/java/android/os/Temperature.aidl | 2 +- native/android/Android.bp | 2 + native/android/libandroid.map.txt | 5 + native/android/thermal.cpp | 261 +++++++++++++++++++++ .../server/power/ThermalManagerService.java | 31 ++- .../server/stats/pull/StatsPullAtomService.java | 4 +- .../server/power/ThermalManagerServiceTest.java | 21 +- 10 files changed, 320 insertions(+), 29 deletions(-) create mode 100644 native/android/thermal.cpp (limited to 'native/android') diff --git a/Android.bp b/Android.bp index 2534140835f8..df716012b962 100644 --- a/Android.bp +++ b/Android.bp @@ -453,6 +453,18 @@ filegroup { path: "core/java", } +filegroup { + name: "libpowermanager_aidl", + srcs: [ + "core/java/android/os/Temperature.aidl", + "core/java/android/os/CoolingDevice.aidl", + "core/java/android/os/IThermalEventListener.aidl", + "core/java/android/os/IThermalStatusListener.aidl", + "core/java/android/os/IThermalService.aidl", + ], + path: "core/java", +} + java_library { name: "framework-minus-apex", defaults: ["framework-defaults"], diff --git a/core/java/android/os/CoolingDevice.aidl b/core/java/android/os/CoolingDevice.aidl index 478e4bd71e6d..c6432fd31d20 100644 --- a/core/java/android/os/CoolingDevice.aidl +++ b/core/java/android/os/CoolingDevice.aidl @@ -16,4 +16,4 @@ package android.os; -parcelable CoolingDevice; +parcelable CoolingDevice cpp_header "android/CoolingDevice.h"; diff --git a/core/java/android/os/IThermalService.aidl b/core/java/android/os/IThermalService.aidl index ad002335a010..c6c8adc4d8a9 100644 --- a/core/java/android/os/IThermalService.aidl +++ b/core/java/android/os/IThermalService.aidl @@ -56,7 +56,7 @@ interface IThermalService { * @return list of {@link android.os.Temperature}. * {@hide} */ - List getCurrentTemperatures(); + Temperature[] getCurrentTemperatures(); /** * Get current temperature with its throttling status on given temperature type. @@ -64,7 +64,7 @@ interface IThermalService { * @return list of {@link android.os.Temperature}. * {@hide} */ - List getCurrentTemperaturesWithType(in int type); + Temperature[] getCurrentTemperaturesWithType(in int type); /** * Register a listener for thermal status change. @@ -94,7 +94,7 @@ interface IThermalService { * @return list of {@link android.os.CoolingDevice}. * {@hide} */ - List getCurrentCoolingDevices(); + CoolingDevice[] getCurrentCoolingDevices(); /** * Get current cooling devices on given type. @@ -102,7 +102,8 @@ interface IThermalService { * @return list of {@link android.os.CoolingDevice}. * {@hide} */ - List getCurrentCoolingDevicesWithType(in int type); + + CoolingDevice[] getCurrentCoolingDevicesWithType(in int type); /** * @param forecastSeconds how many seconds ahead to forecast the provided headroom diff --git a/core/java/android/os/Temperature.aidl b/core/java/android/os/Temperature.aidl index 708c08fbe8b0..5268dd5441e3 100644 --- a/core/java/android/os/Temperature.aidl +++ b/core/java/android/os/Temperature.aidl @@ -16,4 +16,4 @@ package android.os; -parcelable Temperature; +parcelable Temperature cpp_header "android/Temperature.h"; diff --git a/native/android/Android.bp b/native/android/Android.bp index 257ae7332cc1..640861bcc391 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -51,6 +51,7 @@ cc_library_shared { "surface_control.cpp", "system_fonts.cpp", "trace.cpp", + "thermal.cpp" ], shared_libs: [ @@ -72,6 +73,7 @@ cc_library_shared { "libxml2", "libEGL", "libGLESv2", + "libpowermanager", "android.hardware.configstore@1.0", "android.hardware.configstore-utils", ], diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index a8f1d2c7bbba..d56aa86ae6fa 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -280,6 +280,11 @@ LIBANDROID { android_res_nquery; # introduced=29 android_res_nresult; # introduced=29 android_res_nsend; # introduced=29 + AThermal_acquireManager; # introduced=30 + AThermal_releaseManager; # introduced=30 + AThermal_getCurrentThermalStatus; # introduced=30 + AThermal_registerThermalStatusListener; # introduced=30 + AThermal_unregisterThermalStatusListener; # introduced=30 local: *; }; diff --git a/native/android/thermal.cpp b/native/android/thermal.cpp new file mode 100644 index 000000000000..545c423908a0 --- /dev/null +++ b/native/android/thermal.cpp @@ -0,0 +1,261 @@ +/* + * 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. + */ + +#define LOG_TAG "thermal" + +#include +#include + +#include +#include +#include +#include +#include + +using android::sp; + +using namespace android; +using namespace android::os; + +struct ThermalServiceListener : public BnThermalStatusListener { + public: + virtual binder::Status onStatusChange(int32_t status) override; + ThermalServiceListener(AThermalManager *manager) {mMgr = manager;} + private: + AThermalManager *mMgr; +}; + +struct ListenerCallback { + AThermal_StatusCallback callback; + void* data; +}; + +struct AThermalManager { + public: + static AThermalManager* createAThermalManager(); + AThermalManager() = delete; + ~AThermalManager(); + status_t notifyStateChange(int32_t status); + status_t getCurrentThermalStatus(int32_t *status); + status_t addListener(AThermal_StatusCallback, void *data); + status_t removeListener(AThermal_StatusCallback, void *data); + private: + AThermalManager(sp service); + sp mThermalSvc; + sp mServiceListener; + std::vector mListeners; + std::mutex mMutex; +}; + +binder::Status ThermalServiceListener::onStatusChange(int32_t status) { + if (mMgr != nullptr) { + mMgr->notifyStateChange(status); + } + return binder::Status::ok(); +} + +AThermalManager* AThermalManager::createAThermalManager() { + sp binder = + defaultServiceManager()->checkService(String16("thermalservice")); + + if (binder == nullptr) { + ALOGE("%s: Thermal service is not ready ", __FUNCTION__); + return nullptr; + } + return new AThermalManager(interface_cast(binder)); +} + +AThermalManager::AThermalManager(sp service) + : mThermalSvc(service), + mServiceListener(nullptr) { +} + +AThermalManager::~AThermalManager() { + std::unique_lock lock(mMutex); + + mListeners.clear(); + if (mServiceListener != nullptr) { + bool success = false; + mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success); + mServiceListener = nullptr; + } +} + +status_t AThermalManager::notifyStateChange(int32_t status) { + std::unique_lock lock(mMutex); + AThermalStatus thermalStatus = static_cast(status); + + for (auto listener : mListeners) { + listener.callback(listener.data, thermalStatus); + } + return OK; +} + +status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) { + std::unique_lock lock(mMutex); + + if (callback == nullptr) { + // Callback can not be nullptr + return EINVAL; + } + for (const auto& cb : mListeners) { + // Don't re-add callbacks. + if (callback == cb.callback && data == cb.data) { + return EINVAL; + } + } + mListeners.emplace_back(ListenerCallback{callback, data}); + + if (mServiceListener != nullptr) { + return OK; + } + bool success = false; + mServiceListener = new ThermalServiceListener(this); + if (mServiceListener == nullptr) { + return ENOMEM; + } + auto ret = mThermalSvc->registerThermalStatusListener(mServiceListener, &success); + if (!success || !ret.isOk()) { + ALOGE("Failed in registerThermalStatusListener %d", success); + if (ret.exceptionCode() == binder::Status::EX_SECURITY) { + return EPERM; + } + return EPIPE; + } + return OK; +} + +status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) { + std::unique_lock lock(mMutex); + + auto it = std::remove_if(mListeners.begin(), + mListeners.end(), + [&](const ListenerCallback& cb) { + return callback == cb.callback && + data == cb.data; + }); + if (it == mListeners.end()) { + // If the listener and data pointer were not previously added. + return EINVAL; + } + mListeners.erase(it, mListeners.end()); + + if (!mListeners.empty()) { + return OK; + } + if (mServiceListener == nullptr) { + return OK; + } + bool success = false; + auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success); + if (!success || !ret.isOk()) { + ALOGE("Failed in unregisterThermalStatusListener %d", success); + if (ret.exceptionCode() == binder::Status::EX_SECURITY) { + return EPERM; + } + return EPIPE; + } + mServiceListener = nullptr; + return OK; +} + +status_t AThermalManager::getCurrentThermalStatus(int32_t *status) { + binder::Status ret = mThermalSvc->getCurrentThermalStatus(status); + + if (!ret.isOk()) { + if (ret.exceptionCode() == binder::Status::EX_SECURITY) { + return EPERM; + } + return EPIPE; + } + return OK; +} + +/** + * Acquire an instance of the thermal manager. This must be freed using + * {@link AThermal_releaseManager}. + * + * @return manager instance on success, nullptr on failure. + */ +AThermalManager* AThermal_acquireManager() { + auto manager = AThermalManager::createAThermalManager(); + + return manager; +} + +/** + * Release the thermal manager pointer acquired by + * {@link AThermal_acquireManager}. + * + * @param manager The manager to be released. + * + */ +void AThermal_releaseManager(AThermalManager *manager) { + delete manager; +} + +/** + * Gets the current thermal status. + * + * @param manager The manager instance to use to query the thermal status, + * acquired by {@link AThermal_acquireManager}. + * + * @return current thermal status, ATHERMAL_STATUS_ERROR on failure. +*/ +AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) { + int32_t status = 0; + status_t ret = manager->getCurrentThermalStatus(&status); + if (ret != OK) { + return AThermalStatus::ATHERMAL_STATUS_ERROR; + } + return static_cast(status); +} + +/** + * Register the thermal status listener for thermal status change. + * + * @param manager The manager instance to use to register. + * acquired by {@link AThermal_acquireManager}. + * @param callback The callback function to be called when thermal status updated. + * @param data The data pointer to be passed when callback is called. + * + * @return 0 on success + * EINVAL if the listener and data pointer were previously added and not removed. + * EPERM if the required permission is not held. + * EPIPE if communication with the system service has failed. + */ +int AThermal_registerThermalStatusListener(AThermalManager *manager, + AThermal_StatusCallback callback, void *data) { + return manager->addListener(callback, data); +} + +/** + * Unregister the thermal status listener previously resgistered. + * + * @param manager The manager instance to use to unregister. + * acquired by {@link AThermal_acquireManager}. + * @param callback The callback function to be called when thermal status updated. + * @param data The data pointer to be passed when callback is called. + * + * @return 0 on success + * EINVAL if the listener and data pointer were not previously added. + * EPERM if the required permission is not held. + * EPIPE if communication with the system service has failed. + */ +int AThermal_unregisterThermalStatusListener(AThermalManager *manager, + AThermal_StatusCallback callback, void *data) { + return manager->removeListener(callback, data); +} diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java index da3cbf9d03b4..74c3a9ec375b 100644 --- a/services/core/java/com/android/server/power/ThermalManagerService.java +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -370,30 +370,33 @@ public class ThermalManagerService extends SystemService { } @Override - public List getCurrentTemperatures() { + public Temperature[] getCurrentTemperatures() { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long token = Binder.clearCallingIdentity(); try { if (!mHalReady.get()) { - return new ArrayList<>(); + return new Temperature[0]; } - return mHalWrapper.getCurrentTemperatures(false, 0 /* not used */); + final List curr = mHalWrapper.getCurrentTemperatures( + false, 0 /* not used */); + return curr.toArray(new Temperature[curr.size()]); } finally { Binder.restoreCallingIdentity(token); } } @Override - public List getCurrentTemperaturesWithType(int type) { + public Temperature[] getCurrentTemperaturesWithType(int type) { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long token = Binder.clearCallingIdentity(); try { if (!mHalReady.get()) { - return new ArrayList<>(); + return new Temperature[0]; } - return mHalWrapper.getCurrentTemperatures(true, type); + final List curr = mHalWrapper.getCurrentTemperatures(true, type); + return curr.toArray(new Temperature[curr.size()]); } finally { Binder.restoreCallingIdentity(token); } @@ -443,30 +446,34 @@ public class ThermalManagerService extends SystemService { } @Override - public List getCurrentCoolingDevices() { + public CoolingDevice[] getCurrentCoolingDevices() { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long token = Binder.clearCallingIdentity(); try { if (!mHalReady.get()) { - return new ArrayList<>(); + return new CoolingDevice[0]; } - return mHalWrapper.getCurrentCoolingDevices(false, 0); + final List devList = mHalWrapper.getCurrentCoolingDevices( + false, 0); + return devList.toArray(new CoolingDevice[devList.size()]); } finally { Binder.restoreCallingIdentity(token); } } @Override - public List getCurrentCoolingDevicesWithType(int type) { + public CoolingDevice[] getCurrentCoolingDevicesWithType(int type) { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final long token = Binder.clearCallingIdentity(); try { if (!mHalReady.get()) { - return new ArrayList<>(); + return new CoolingDevice[0]; } - return mHalWrapper.getCurrentCoolingDevices(true, type); + final List devList = mHalWrapper.getCurrentCoolingDevices( + true, type); + return devList.toArray(new CoolingDevice[devList.size()]); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 47a26f576949..2b111f7fbc12 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -1515,7 +1515,7 @@ public class StatsPullAtomService extends SystemService { } final long callingToken = Binder.clearCallingIdentity(); try { - List temperatures = thermalService.getCurrentTemperatures(); + Temperature temperatures[] = thermalService.getCurrentTemperatures(); for (Temperature temp : temperatures) { StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) @@ -1553,7 +1553,7 @@ public class StatsPullAtomService extends SystemService { } final long callingToken = Binder.clearCallingIdentity(); try { - List devices = thermalService.getCurrentCoolingDevices(); + CoolingDevice devices[] = thermalService.getCurrentCoolingDevices(); for (CoolingDevice device : devices) { StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java index 624cb83f9e19..9e067304fc7f 100644 --- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java @@ -297,9 +297,11 @@ public class ThermalManagerServiceTest { @Test public void testGetCurrentTemperatures() throws RemoteException { assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(false, 0), - mService.mService.getCurrentTemperatures()); - assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN), - mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN)); + Arrays.asList(mService.mService.getCurrentTemperatures())); + assertListEqualsIgnoringOrder( + mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN), + Arrays.asList(mService.mService.getCurrentTemperaturesWithType( + Temperature.TYPE_SKIN))); } @Test @@ -331,21 +333,22 @@ public class ThermalManagerServiceTest { assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1)); assertTrue(mService.mService.unregisterThermalEventListener(mEventListener1)); assertTrue(mService.mService.unregisterThermalStatusListener(mStatusListener1)); - assertEquals(0, mService.mService.getCurrentTemperatures().size()); - assertEquals(0, - mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN).size()); + assertEquals(0, Arrays.asList(mService.mService.getCurrentTemperatures()).size()); + assertEquals(0, Arrays.asList(mService.mService.getCurrentTemperaturesWithType( + Temperature.TYPE_SKIN)).size()); assertEquals(Temperature.THROTTLING_NONE, mService.mService.getCurrentThermalStatus()); } @Test public void testGetCurrentCoolingDevices() throws RemoteException { assertListEqualsIgnoringOrder(mFakeHal.getCurrentCoolingDevices(false, 0), - mService.mService.getCurrentCoolingDevices()); + Arrays.asList(mService.mService.getCurrentCoolingDevices())); assertListEqualsIgnoringOrder( mFakeHal.getCurrentCoolingDevices(false, CoolingDevice.TYPE_BATTERY), - mService.mService.getCurrentCoolingDevices()); + Arrays.asList(mService.mService.getCurrentCoolingDevices())); assertListEqualsIgnoringOrder( mFakeHal.getCurrentCoolingDevices(true, CoolingDevice.TYPE_CPU), - mService.mService.getCurrentCoolingDevicesWithType(CoolingDevice.TYPE_CPU)); + Arrays.asList(mService.mService.getCurrentCoolingDevicesWithType( + CoolingDevice.TYPE_CPU))); } } -- cgit v1.2.3-59-g8ed1b From ee538a3a8578e684b0d04743a3e5904d622960ba Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Wed, 19 Feb 2020 11:51:17 -0500 Subject: Cleanup header and build targets for libhwui clients. Targets that will also be contained within the UI module are allowed to access internal headers. All other targets that depend on libhwui are restricted to using the APEX headers. Bug: 137655431 Test: CtsUiRenderingTestCases Change-Id: Id92e9874dafb98bd79839d45ab8f22ab999689de --- libs/input/Android.bp | 1 + libs/input/tests/Android.bp | 1 + native/android/Android.bp | 2 ++ native/graphics/jni/Android.bp | 2 ++ native/webview/plat_support/Android.bp | 4 +++- native/webview/plat_support/graphics_utils.cpp | 4 +--- rs/jni/Android.mk | 1 + 7 files changed, 11 insertions(+), 4 deletions(-) (limited to 'native/android') diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 6bb896fd7b29..88d6033ed9fb 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -23,6 +23,7 @@ cc_library_shared { "libandroid_runtime", "libbinder", "libcutils", + "libhwui", "liblog", "libutils", "libgui", diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index b1e3d6fe845a..213b3adfb2a8 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -20,6 +20,7 @@ cc_test { shared_libs: [ "libandroid_runtime", "libinputservice", + "libhwui", "libgui", "libutils", ], diff --git a/native/android/Android.bp b/native/android/Android.bp index 257ae7332cc1..0a8ef38303a1 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -81,6 +81,8 @@ cc_library_shared { "libarect", ], + header_libs: [ "libhwui_internal_headers" ], + whole_static_libs: ["libnativedisplay", "libnativewindow"], export_static_lib_headers: ["libarect"], diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp index 376ea77740c2..15b473c2a6ab 100644 --- a/native/graphics/jni/Android.bp +++ b/native/graphics/jni/Android.bp @@ -37,6 +37,8 @@ cc_library_shared { "liblog", ], + header_libs: [ "libhwui_internal_headers" ], + static_libs: ["libarect"], arch: { diff --git a/native/webview/plat_support/Android.bp b/native/webview/plat_support/Android.bp index 88decc86c387..1a3b36d046e1 100644 --- a/native/webview/plat_support/Android.bp +++ b/native/webview/plat_support/Android.bp @@ -30,12 +30,14 @@ cc_library_shared { "graphic_buffer_impl.cpp", ], + header_libs: [ "libhwui_internal_headers" ], + shared_libs: [ "libandroidfw", - "libandroid_runtime", "libcutils", "libhwui", "liblog", + "libnativehelper", "libui", "libutils", "libvulkan", diff --git a/native/webview/plat_support/graphics_utils.cpp b/native/webview/plat_support/graphics_utils.cpp index 56825cee4520..8d7a59e46e72 100644 --- a/native/webview/plat_support/graphics_utils.cpp +++ b/native/webview/plat_support/graphics_utils.cpp @@ -25,11 +25,9 @@ #include #include #include -#include "android/graphics/GraphicsJNI.h" +#include "GraphicsJNI.h" #include "graphic_buffer_impl.h" #include "SkCanvasStateUtils.h" -#include "SkGraphics.h" -#include "SkPicture.h" #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk index f9ef0b7b8e9d..a4bea661583b 100644 --- a/rs/jni/Android.mk +++ b/rs/jni/Android.mk @@ -11,6 +11,7 @@ LOCAL_SHARED_LIBRARIES := \ libnativehelper \ libRS \ libcutils \ + libhwui \ liblog \ libutils \ libui \ -- cgit v1.2.3-59-g8ed1b From cf3ad873ddd7f1abf3804936befa511b2fbb12b6 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 27 Apr 2020 22:36:17 -0700 Subject: Dispatch refresh rate callbacks from DMS AChoreographer will consume these callbacks in lieu of going through SF for the callbacks. This is so that DMS can update its view of display configs before apps receive the refresh rate callback so that apps can get consistent information. Bug: 154874011 Test: ChoreographerNativeTest Test: Manually verify that HWUI is receiving callbacks Change-Id: I992c247fd16ef414f94a259bbd300bea3e4c9467 --- .../hardware/display/DisplayManagerGlobal.java | 85 +++++++++++++++++----- core/jni/Android.bp | 1 + core/jni/AndroidRuntime.cpp | 32 ++++---- ...droid_hardware_display_DisplayManagerGlobal.cpp | 55 ++++++++++++++ core/jni/include/android_runtime/AndroidRuntime.h | 11 ++- native/android/Android.bp | 7 +- native/android/choreographer.cpp | 52 +++++++++++++ native/android/surface_texture.cpp | 52 +++++++++++++ 8 files changed, 253 insertions(+), 42 deletions(-) create mode 100644 core/jni/android_hardware_display_DisplayManagerGlobal.cpp create mode 100644 native/android/choreographer.cpp create mode 100644 native/android/surface_texture.cpp (limited to 'native/android') diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 4d645e6052a7..0f9c7088a1d0 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -34,7 +34,6 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; -import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.util.SparseArray; @@ -74,6 +73,8 @@ public final class DisplayManagerGlobal { @UnsupportedAppUsage private static DisplayManagerGlobal sInstance; + // Guarded by mLock + private boolean mDispatchNativeCallbacks = false; private final Object mLock = new Object(); @UnsupportedAppUsage @@ -143,27 +144,35 @@ public final class DisplayManagerGlobal { @UnsupportedAppUsage public DisplayInfo getDisplayInfo(int displayId) { synchronized (mLock) { - DisplayInfo info = null; - if (mDisplayCache != null) { - info = mDisplayCache.query(displayId); - } else { - try { - info = mDm.getDisplayInfo(displayId); - } catch (RemoteException ex) { - ex.rethrowFromSystemServer(); - } - } - if (info == null) { - return null; + return getDisplayInfoLocked(displayId); + } + } + + /** + * Gets information about a particular logical display + * See {@link getDisplayInfo}, but assumes that {@link mLock} is held + */ + private @Nullable DisplayInfo getDisplayInfoLocked(int displayId) { + DisplayInfo info = null; + if (mDisplayCache != null) { + info = mDisplayCache.query(displayId); + } else { + try { + info = mDm.getDisplayInfo(displayId); + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); } + } + if (info == null) { + return null; + } - registerCallbackIfNeededLocked(); + registerCallbackIfNeededLocked(); - if (DEBUG) { - Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info); - } - return info; + if (DEBUG) { + Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info); } + return info; } /** @@ -341,6 +350,20 @@ public final class DisplayManagerGlobal { for (int i = 0; i < numListeners; i++) { mDisplayListeners.get(i).sendDisplayEvent(displayId, event); } + if (event == EVENT_DISPLAY_CHANGED && mDispatchNativeCallbacks) { + // Choreographer only supports a single display, so only dispatch refresh rate + // changes for the default display. + if (displayId == Display.DEFAULT_DISPLAY) { + // We can likely save a binder hop if we attach the refresh rate onto the + // listener. + DisplayInfo display = getDisplayInfoLocked(displayId); + if (display != null) { + float refreshRate = display.getMode().getRefreshRate(); + // Signal native callbacks if we ever set a refresh rate. + nSignalNativeCallbacks(refreshRate); + } + } + } } } @@ -800,4 +823,30 @@ public final class DisplayManagerGlobal { public void disableLocalDisplayInfoCaches() { mDisplayCache = null; } + + private static native void nSignalNativeCallbacks(float refreshRate); + + // Called from AChoreographer via JNI. + // Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS. + private void registerNativeChoreographerForRefreshRateCallbacks() { + synchronized (mLock) { + registerCallbackIfNeededLocked(); + mDispatchNativeCallbacks = true; + DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY); + if (display != null) { + // We need to tell AChoreographer instances the current refresh rate so that apps + // can get it for free once a callback first registers. + float refreshRate = display.getMode().getRefreshRate(); + nSignalNativeCallbacks(refreshRate); + } + } + } + + // Called from AChoreographer via JNI. + // Unregisters AChoreographer from receiving refresh rate callbacks. + private void unregisterNativeChoreographerForRefreshRateCallbacks() { + synchronized (mLock) { + mDispatchNativeCallbacks = false; + } + } } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index bd7bc4cf4ceb..5a66f4394ead 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -158,6 +158,7 @@ cc_library_shared { "android_hardware_camera2_legacy_LegacyCameraDevice.cpp", "android_hardware_camera2_legacy_PerfMeasurement.cpp", "android_hardware_camera2_DngCreator.cpp", + "android_hardware_display_DisplayManagerGlobal.cpp", "android_hardware_display_DisplayViewport.cpp", "android_hardware_HardwareBuffer.cpp", "android_hardware_SensorManager.cpp", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 6fcaddf34322..a420ba67868f 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -18,39 +18,37 @@ #define LOG_TAG "AndroidRuntime" #define LOG_NDEBUG 1 -#include - #include #include #include +#include +#include #include #include #include -#include -#include -#include #include -#include +#include #include -#include - -#include "jni.h" +#include +#include #include #include -#include "android_util_Binder.h" - -#include +#include #include +#include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include +#include "android_util_Binder.h" +#include "jni.h" + using namespace android; using android::base::GetProperty; @@ -78,6 +76,7 @@ extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env); extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *env); extern int register_android_hardware_camera2_legacy_PerfMeasurement(JNIEnv *env); extern int register_android_hardware_camera2_DngCreator(JNIEnv *env); +extern int register_android_hardware_display_DisplayManagerGlobal(JNIEnv* env); extern int register_android_hardware_HardwareBuffer(JNIEnv *env); extern int register_android_hardware_SensorManager(JNIEnv *env); extern int register_android_hardware_SerialPort(JNIEnv *env); @@ -1519,6 +1518,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice), REG_JNI(register_android_hardware_camera2_legacy_PerfMeasurement), REG_JNI(register_android_hardware_camera2_DngCreator), + REG_JNI(register_android_hardware_display_DisplayManagerGlobal), REG_JNI(register_android_hardware_HardwareBuffer), REG_JNI(register_android_hardware_SensorManager), REG_JNI(register_android_hardware_SerialPort), diff --git a/core/jni/android_hardware_display_DisplayManagerGlobal.cpp b/core/jni/android_hardware_display_DisplayManagerGlobal.cpp new file mode 100644 index 000000000000..9f316714a55c --- /dev/null +++ b/core/jni/android_hardware_display_DisplayManagerGlobal.cpp @@ -0,0 +1,55 @@ +/* + * 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 + * + * 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 "DisplayManagerGlobal-JNI" + +#include +#include +#include + +#include + +#include "core_jni_helpers.h" + +using namespace android; + +namespace android { + +// Dispatches the current refresh rate for the default display to all +// choreographer instances +void android_hardware_display_DisplayManagerGlobal_signalNativeCallbacks(JNIEnv* env, jobject, + jfloat refreshRate) { + const constexpr int64_t kNanosPerSecond = 1000 * 1000 * 1000; + const nsecs_t vsyncPeriod = kNanosPerSecond / refreshRate; + + AChoreographer_signalRefreshRateCallbacks(vsyncPeriod); +} + +} // namespace android + +// ---------------------------------------------------------------------------- + +const char* const kClassPathName = "android/hardware/display/DisplayManagerGlobal"; + +static const JNINativeMethod gMethods[] = { + {"nSignalNativeCallbacks", "(F)V", + (void*)android_hardware_display_DisplayManagerGlobal_signalNativeCallbacks}, +}; + +int register_android_hardware_display_DisplayManagerGlobal(JNIEnv* env) { + AChoreographer_initJVM(env); + return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); +} diff --git a/core/jni/include/android_runtime/AndroidRuntime.h b/core/jni/include/android_runtime/AndroidRuntime.h index 235127266926..d86d9340e667 100644 --- a/core/jni/include/android_runtime/AndroidRuntime.h +++ b/core/jni/include/android_runtime/AndroidRuntime.h @@ -19,15 +19,14 @@ #ifndef _RUNTIME_ANDROID_RUNTIME_H #define _RUNTIME_ANDROID_RUNTIME_H -#include #include -#include +#include +#include +#include #include +#include #include #include -#include -#include - namespace android { @@ -154,6 +153,6 @@ private: static int javaThreadShell(void* args); }; -} +} // namespace android #endif diff --git a/native/android/Android.bp b/native/android/Android.bp index ed73f39e57f8..797d3fd8c2ff 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -37,6 +37,7 @@ cc_library_shared { srcs: [ "asset_manager.cpp", + "choreographer.cpp", "configuration.cpp", "hardware_buffer_jni.cpp", "input.cpp", @@ -49,6 +50,7 @@ cc_library_shared { "sharedmem.cpp", "storage_manager.cpp", "surface_control.cpp", + "surface_texture.cpp", "system_fonts.cpp", "trace.cpp", "thermal.cpp" @@ -76,6 +78,7 @@ cc_library_shared { "libpowermanager", "android.hardware.configstore@1.0", "android.hardware.configstore-utils", + "libnativedisplay", ], static_libs: [ @@ -83,9 +86,9 @@ cc_library_shared { "libarect", ], - header_libs: [ "libhwui_internal_headers" ], + header_libs: [ "libhwui_internal_headers",], - whole_static_libs: ["libnativedisplay", "libnativewindow"], + whole_static_libs: ["libnativewindow"], export_static_lib_headers: ["libarect"], diff --git a/native/android/choreographer.cpp b/native/android/choreographer.cpp new file mode 100644 index 000000000000..38641de0efb3 --- /dev/null +++ b/native/android/choreographer.cpp @@ -0,0 +1,52 @@ +/* + * 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 + * + * 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. + */ + +#include + +using namespace android; + +AChoreographer* AChoreographer_getInstance() { + return AChoreographer_routeGetInstance(); +} +void AChoreographer_postFrameCallback(AChoreographer* choreographer, + AChoreographer_frameCallback callback, void* data) { + return AChoreographer_routePostFrameCallback(choreographer, callback, data); +} +void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, + AChoreographer_frameCallback callback, void* data, + long delayMillis) { + return AChoreographer_routePostFrameCallbackDelayed(choreographer, callback, data, delayMillis); +} +void AChoreographer_postFrameCallback64(AChoreographer* choreographer, + AChoreographer_frameCallback64 callback, void* data) { + return AChoreographer_routePostFrameCallback64(choreographer, callback, data); +} +void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, + AChoreographer_frameCallback64 callback, void* data, + uint32_t delayMillis) { + return AChoreographer_routePostFrameCallbackDelayed64(choreographer, callback, data, + delayMillis); +} +void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer, + AChoreographer_refreshRateCallback callback, + void* data) { + return AChoreographer_routeRegisterRefreshRateCallback(choreographer, callback, data); +} +void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, + AChoreographer_refreshRateCallback callback, + void* data) { + return AChoreographer_routeUnregisterRefreshRateCallback(choreographer, callback, data); +} diff --git a/native/android/surface_texture.cpp b/native/android/surface_texture.cpp new file mode 100644 index 000000000000..ff35204b2ec9 --- /dev/null +++ b/native/android/surface_texture.cpp @@ -0,0 +1,52 @@ +/* + * 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 + * + * 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. + */ + +#include +#include + +using namespace android; + +ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) { + return ASurfaceTexture_routeAcquireANativeWindow(st); +} + +int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName) { + return ASurfaceTexture_routeAttachToGLContext(st, texName); +} + +int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) { + return ASurfaceTexture_routeDetachFromGLContext(st); +} + +void ASurfaceTexture_release(ASurfaceTexture* st) { + return ASurfaceTexture_routeRelease(st); +} + +int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) { + return ASurfaceTexture_routeUpdateTexImage(st); +} + +void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) { + return ASurfaceTexture_routeGetTransformMatrix(st, mtx); +} + +int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) { + return ASurfaceTexture_routeGetTimestamp(st); +} + +ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) { + return ASurfaceTexture_routeFromSurfaceTexture(env, surfacetexture); +} -- cgit v1.2.3-59-g8ed1b