Protect static global access with a global flag.
- The global objects are protected by a global flag, during
application teardown.
- The following APIs, which could potentially be called during
application teardown, will be NO-OP if global objects are no
longer alive.
rsContextCreate
rsContextCreateGL
rsContextDestroy
- Added a test of the problematic use-cases.
Detailed discussion:
https://goto.google.com/rs-static-destructor
Bug: 62027113
Test: mm
Test: Before the change to rsApiStubs.cpp, the test hangs during
termination.
Test: After the change to rsApiStubs.cpp, the test passes without any
problems.
Change-Id: I7a43a61d9ccf848c17a88e047e97d087132addda
(cherry picked from commit 296cd02e03565153f7dff971988adf8e8c6c365a)
diff --git a/rsApiStubs.cpp b/rsApiStubs.cpp
index e0753b0..28f1b1e 100644
--- a/rsApiStubs.cpp
+++ b/rsApiStubs.cpp
@@ -57,6 +57,28 @@
// supported on Android are built on top of pthread, std::mutex is safe for them.
static std::mutex contextMapMutex;
+// globalObjAlive is a global flag indicating whether the global objects,
+// contextMap & contextMapMutex, are still alive.
+// For the protected functions during application teardown, this
+// flag will be checked before accessing the global objects.
+static bool globalObjAlive;
+
+// GlobalObjGuard manipulates the globalObjAlive flag during construction and
+// destruction. If the guard object is destroyed, globalObjAlive will be set
+// to false, which will make the protected functions NO-OP.
+// https://goto.google.com/rs-static-destructor
+class GlobalObjGuard {
+ public:
+ GlobalObjGuard() {
+ globalObjAlive = true;
+ }
+
+ ~GlobalObjGuard() {
+ globalObjAlive = false;
+ }
+};
+static GlobalObjGuard guard;
+
// API to find high-level context (RsContextWrapper) given a low level context.
// This API is only intended to be used by RenderScript debugger.
extern "C" RsContext rsDebugGetHighLevelContext(RsContext context) {
@@ -96,6 +118,11 @@
extern "C" RsContext rsContextCreate(RsDevice vdev, uint32_t version, uint32_t sdkVersion,
RsContextType ct, uint32_t flags)
{
+ if (!globalObjAlive) {
+ ALOGE("rsContextCreate is not allowed during process teardown.");
+ return nullptr;
+ }
+
RsHidlAdaptation& instance = RsHidlAdaptation::GetInstance();
RsContext context = instance.GetEntryFuncs()->ContextCreate(vdev, version, sdkVersion, ct, flags);
// Wait for debugger to attach if RS_CONTEXT_WAIT_FOR_ATTACH flag set.
@@ -155,6 +182,10 @@
extern "C" void rsContextDestroy (RsContext ctxWrapper)
{
+ if (!globalObjAlive) {
+ return;
+ }
+
RS_DISPATCH(ctxWrapper, ContextDestroy);
// Lock contextMap when deleting an existing entry.
@@ -683,6 +714,11 @@
RsContext rsContextCreateGL(RsDevice vdev, uint32_t version, uint32_t sdkVersion,
RsSurfaceConfig sc, uint32_t dpi)
{
+ if (!globalObjAlive) {
+ ALOGE("rsContextCreateGL is not allowed during process teardown.");
+ return nullptr;
+ }
+
RsFallbackAdaptation& instance = RsFallbackAdaptation::GetInstance();
RsContext context = instance.GetEntryFuncs()->ContextCreateGL(vdev, version, sdkVersion, sc, dpi);
diff --git a/rsHidlAdaptation.h b/rsHidlAdaptation.h
index 48c4b6a..372a298 100644
--- a/rsHidlAdaptation.h
+++ b/rsHidlAdaptation.h
@@ -32,6 +32,10 @@
* 1. Load the dispatch table with HIDL implementation or CPU fallback.
* 2. Convert input paramters to HIDL types, when using HIDL path.
* 3. Convert output parameters from HIDL types to RS types, when using HIDL path.
+ *
+ * Access of static member objects is protected by global teardown flag.
+ * https://goto.google.com/rs-static-destructor
+ *
*/
class RsHidlAdaptation
{
diff --git a/tests/cpp_api/cpp-globalguard/Android.mk b/tests/cpp_api/cpp-globalguard/Android.mk
new file mode 100644
index 0000000..118c9fb
--- /dev/null
+++ b/tests/cpp_api/cpp-globalguard/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= rstest-cpp-globalguard
+
+LOCAL_SDK_VERSION := 21
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+LOCAL_SRC_FILES:= \
+ multiply.rs \
+ compute.cpp
+
+LOCAL_STATIC_LIBRARIES := \
+ libRScpp_static
+
+LOCAL_LDFLAGS += -llog
+
+include frameworks/rs/tests/cpp_api/common.mk
+include $(BUILD_EXECUTABLE)
diff --git a/tests/cpp_api/cpp-globalguard/compute.cpp b/tests/cpp_api/cpp-globalguard/compute.cpp
new file mode 100644
index 0000000..8b9789c
--- /dev/null
+++ b/tests/cpp_api/cpp-globalguard/compute.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+// This file is based on frameworks/rs/tests/cpp_api/cppallocation/compute.cpp.
+
+#include "RenderScript.h"
+
+#include "ScriptC_multiply.h"
+
+sp<RS> rs;
+sp<const Element> e;
+sp<const Type> t;
+sp<Allocation> ain;
+sp<Allocation> aout;
+sp<ScriptC_multiply> sc;
+
+int main(int argc, char** argv)
+{
+ uint32_t numElems = 1024;
+
+ if (argc >= 2) {
+ int tempNumElems = atoi(argv[1]);
+ if (tempNumElems < 1) {
+ printf("numElems must be greater than 0\n");
+ return 1;
+ }
+ numElems = (uint32_t) tempNumElems;
+ }
+
+ rs = new RS();
+
+ if (!rs->init("/system/bin")) {
+ printf("Could not initialize RenderScript\n");
+ return 1;
+ }
+
+ e = Element::U32(rs);
+
+ Type::Builder tb(rs, e);
+ tb.setX(numElems);
+ t = tb.create();
+
+ ain = Allocation::createTyped(rs, t);
+ aout = Allocation::createTyped(rs, t);
+
+ sc = new ScriptC_multiply(rs);
+
+ uint32_t* buf = new uint32_t[numElems];
+ for (uint32_t ct=0; ct < numElems; ct++) {
+ buf[ct] = (uint32_t)ct;
+ }
+
+ ain->copy1DRangeFrom(0, numElems, buf);
+
+ sc->forEach_multiply(ain, aout);
+
+ aout->copy1DRangeTo(0, numElems, buf);
+
+ for (uint32_t ct=0; ct < numElems; ct++) {
+ if (buf[ct] != ct * 2) {
+ printf("Mismatch at location %d: %u\n", ct, buf[ct]);
+ return 1;
+ }
+ }
+
+ printf("Test successful with %u elems!\n", numElems);
+}
diff --git a/tests/cpp_api/cpp-globalguard/multiply.rs b/tests/cpp_api/cpp-globalguard/multiply.rs
new file mode 100644
index 0000000..6ee7fb5
--- /dev/null
+++ b/tests/cpp_api/cpp-globalguard/multiply.rs
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(unused)
+#pragma rs_fp_relaxed
+
+uint32_t RS_KERNEL multiply(uint32_t in) {
+ return in * 2;
+}
+
+