summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/res/ResourcesImpl.java66
-rw-r--r--core/java/android/os/HidlSupport.java23
-rw-r--r--core/java/android/os/HwBinder.java7
-rw-r--r--core/java/android/os/HwRemoteBinder.java5
-rw-r--r--core/jni/android_os_HwBinder.cpp14
-rw-r--r--core/jni/android_os_HwRemoteBinder.cpp49
-rw-r--r--services/core/jni/com_android_server_SystemServer.cpp2
-rw-r--r--services/java/com/android/server/SystemServer.java3
8 files changed, 155 insertions, 14 deletions
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 386239cf4f93..3239212adf66 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -49,6 +49,8 @@ import android.util.TypedValue;
import android.util.Xml;
import android.view.DisplayAdjustments;
+import com.android.internal.util.GrowingArrayUtils;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -117,6 +119,13 @@ public class ResourcesImpl {
private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
new ConfigurationBoundResourceCache<>();
+ // A stack of all the resourceIds already referenced when parsing a resource. This is used to
+ // detect circular references in the xml.
+ // Using a ThreadLocal variable ensures that we have different stacks for multiple parallel
+ // calls to ResourcesImpl
+ private final ThreadLocal<LookupStack> mLookupStack =
+ ThreadLocal.withInitial(() -> new LookupStack());
+
/** Size of the cyclical cache used to map XML files to blocks. */
private static final int XML_BLOCK_CACHE_SIZE = 4;
@@ -784,19 +793,29 @@ public class ResourcesImpl {
final Drawable dr;
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
+ LookupStack stack = mLookupStack.get();
try {
- if (file.endsWith(".xml")) {
- final XmlResourceParser rp = loadXmlResourceParser(
- file, id, value.assetCookie, "drawable");
- dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
- rp.close();
- } else {
- final InputStream is = mAssets.openNonAsset(
- value.assetCookie, file, AssetManager.ACCESS_STREAMING);
- dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
- is.close();
+ // Perform a linear search to check if we have already referenced this resource before.
+ if (stack.contains(id)) {
+ throw new Exception("Recursive reference in drawable");
}
- } catch (Exception | StackOverflowError e) {
+ stack.push(id);
+ try {
+ if (file.endsWith(".xml")) {
+ final XmlResourceParser rp = loadXmlResourceParser(
+ file, id, value.assetCookie, "drawable");
+ dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
+ rp.close();
+ } else {
+ final InputStream is = mAssets.openNonAsset(
+ value.assetCookie, file, AssetManager.ACCESS_STREAMING);
+ dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
+ is.close();
+ }
+ } finally {
+ stack.pop();
+ }
+ } catch (Exception e) {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
final NotFoundException rnf = new NotFoundException(
"File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
@@ -1377,4 +1396,29 @@ public class ResourcesImpl {
}
}
}
+
+ private static class LookupStack {
+
+ // Pick a reasonable default size for the array, it is grown as needed.
+ private int[] mIds = new int[4];
+ private int mSize = 0;
+
+ public void push(int id) {
+ mIds = GrowingArrayUtils.append(mIds, mSize, id);
+ mSize++;
+ }
+
+ public boolean contains(int id) {
+ for (int i = 0; i < mSize; i++) {
+ if (mIds[i] == id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void pop() {
+ mSize--;
+ }
+ }
}
diff --git a/core/java/android/os/HidlSupport.java b/core/java/android/os/HidlSupport.java
index 7dec4d724f15..3544ea1e03e3 100644
--- a/core/java/android/os/HidlSupport.java
+++ b/core/java/android/os/HidlSupport.java
@@ -156,4 +156,27 @@ public class HidlSupport {
// Should not reach here.
throw new UnsupportedOperationException();
}
+
+ /**
+ * Test that two interfaces are equal. This is the Java equivalent to C++
+ * interfacesEqual function.
+ * This essentially calls .equals on the internal binder objects (via Binder()).
+ * - If both interfaces are proxies, asBinder() returns a {@link HwRemoteBinder}
+ * object, and they are compared in {@link HwRemoteBinder#equals}.
+ * - If both interfaces are stubs, asBinder() returns the object itself. By default,
+ * auto-generated IFoo.Stub does not override equals(), but an implementation can
+ * optionally override it, and {@code interfacesEqual} will use it here.
+ */
+ public static boolean interfacesEqual(IHwInterface lft, Object rgt) {
+ if (lft == rgt) {
+ return true;
+ }
+ if (lft == null || rgt == null) {
+ return false;
+ }
+ if (!(rgt instanceof IHwInterface)) {
+ return false;
+ }
+ return Objects.equals(lft.asBinder(), ((IHwInterface) rgt).asBinder());
+ }
}
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 5e2a0815b60d..dd9e774141e1 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -63,6 +63,13 @@ public abstract class HwBinder implements IHwBinder {
public static native final void joinRpcThreadpool();
+ /**
+ * Call configureRpcThreadpool, then actually spawn
+ * (maxThreads - (callerWillJoin ? 0 : 1)) threads.
+ */
+ public static final native void startRpcThreadPool(
+ long maxThreads, boolean callerWillJoin);
+
// Returns address of the "freeFunction".
private static native final long native_init();
diff --git a/core/java/android/os/HwRemoteBinder.java b/core/java/android/os/HwRemoteBinder.java
index 2f89ce6270be..a07e42c720c5 100644
--- a/core/java/android/os/HwRemoteBinder.java
+++ b/core/java/android/os/HwRemoteBinder.java
@@ -63,4 +63,9 @@ public class HwRemoteBinder implements IHwBinder {
}
private long mNativeContext;
+
+ @Override
+ public final native boolean equals(Object other);
+ @Override
+ public final native int hashCode();
}
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 08d952791ef6..f6783e15e294 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -344,6 +344,17 @@ void JHwBinder_native_joinRpcThreadpool() {
IPCThreadState::self()->joinThreadPool();
}
+void JHwBinder_native_startRpcThreadPool(JNIEnv *, jclass,
+ jlong maxThreads, jboolean callerWillJoin) {
+ CHECK(maxThreads > 0);
+ ProcessState::self()->setThreadPoolConfiguration(maxThreads,
+ callerWillJoin /* callerJoinsPool */);
+ ssize_t threadsNeeded = maxThreads - (callerWillJoin ? 0 : 1);
+ for (ssize_t i = 0; i < threadsNeeded; ++i) {
+ ProcessState::self()->spawnPooledThread(false /* isMain */);
+ }
+}
+
static void JHwBinder_report_sysprop_change(JNIEnv * /*env*/, jclass /*clazz*/)
{
report_sysprop_change();
@@ -369,6 +380,9 @@ static JNINativeMethod gMethods[] = {
{ "joinRpcThreadpool", "()V",
(void *)JHwBinder_native_joinRpcThreadpool },
+ { "startRpcThreadPool", "(JZ)V",
+ (void *)JHwBinder_native_startRpcThreadPool },
+
{ "native_report_sysprop_change", "()V",
(void *)JHwBinder_report_sysprop_change },
};
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index cf59a56a13dc..ca5e1e45dcdc 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -22,9 +22,13 @@
#include "android_os_HwParcel.h"
-#include <nativehelper/JNIHelp.h>
+#include <android/hidl/base/1.0/IBase.h>
+#include <android/hidl/base/1.0/BpHwBase.h>
+#include <android/hidl/base/1.0/BnHwBase.h>
#include <android_runtime/AndroidRuntime.h>
#include <hidl/Status.h>
+#include <hidl/HidlTransportSupport.h>
+#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -413,6 +417,44 @@ static jboolean JHwRemoteBinder_unlinkToDeath(JNIEnv* env, jobject thiz,
return res;
}
+static sp<hidl::base::V1_0::IBase> toIBase(JNIEnv* env, jclass hwRemoteBinderClazz, jobject jbinder)
+{
+ if (jbinder == nullptr) {
+ return nullptr;
+ }
+ if (!env->IsInstanceOf(jbinder, hwRemoteBinderClazz)) {
+ return nullptr;
+ }
+ sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, jbinder);
+ sp<hardware::IBinder> cbinder = context->getBinder();
+ return hardware::fromBinder<hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase,
+ hidl::base::V1_0::BnHwBase>(cbinder);
+}
+
+// equals iff other is also a non-null android.os.HwRemoteBinder object
+// and getBinder() returns the same object.
+// In particular, if other is an android.os.HwBinder object (for stubs) then
+// it returns false.
+static jboolean JHwRemoteBinder_equals(JNIEnv* env, jobject thiz, jobject other)
+{
+ if (env->IsSameObject(thiz, other)) {
+ return true;
+ }
+ if (other == NULL) {
+ return false;
+ }
+
+ ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
+
+ return hardware::interfacesEqual(toIBase(env, clazz.get(), thiz), toIBase(env, clazz.get(), other));
+}
+
+static jint JHwRemoteBinder_hashCode(JNIEnv* env, jobject thiz) {
+ jlong longHash = reinterpret_cast<jlong>(
+ JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder().get());
+ return static_cast<jint>(longHash ^ (longHash >> 32)); // See Long.hashCode()
+}
+
static JNINativeMethod gMethods[] = {
{ "native_init", "()J", (void *)JHwRemoteBinder_native_init },
@@ -430,6 +472,11 @@ static JNINativeMethod gMethods[] = {
{"unlinkToDeath",
"(Landroid/os/IHwBinder$DeathRecipient;)Z",
(void*)JHwRemoteBinder_unlinkToDeath},
+
+ {"equals", "(Ljava/lang/Object;)Z",
+ (void*)JHwRemoteBinder_equals},
+
+ {"hashCode", "()I", (void*)JHwRemoteBinder_hashCode},
};
namespace android {
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 3901cebcc787..d4ffa70417e1 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -48,8 +48,6 @@ static void android_server_SystemServer_startHidlServices(JNIEnv* env, jobject /
status_t err;
- configureRpcThreadpool(5, false /* callerWillJoin */);
-
JavaVM *vm;
LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index de5d879a05af..63f834eecd14 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -660,6 +660,9 @@ public final class SystemServer {
mSystemServiceManager.startService(DropBoxManagerService.class);
traceEnd();
+ // First hwbinder call is in BatteryService.
+ android.os.HwBinder.startRpcThreadPool(5, false /* callerWillJoin */);
+
traceBeginAndSlog("StartBatteryService");
// Tracks the battery level. Requires LightService.
mSystemServiceManager.startService(BatteryService.class);