diff options
| -rw-r--r-- | core/java/android/content/res/ResourcesImpl.java | 66 | ||||
| -rw-r--r-- | core/java/android/os/HidlSupport.java | 23 | ||||
| -rw-r--r-- | core/java/android/os/HwBinder.java | 7 | ||||
| -rw-r--r-- | core/java/android/os/HwRemoteBinder.java | 5 | ||||
| -rw-r--r-- | core/jni/android_os_HwBinder.cpp | 14 | ||||
| -rw-r--r-- | core/jni/android_os_HwRemoteBinder.cpp | 49 | ||||
| -rw-r--r-- | services/core/jni/com_android_server_SystemServer.cpp | 2 | ||||
| -rw-r--r-- | services/java/com/android/server/SystemServer.java | 3 |
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); |