Merge "Compile android.test.*.stubs into dex"
diff --git a/Android.bp b/Android.bp
index f11b6fe..48757b4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -27,6 +27,7 @@
java_library {
name: "framework",
+ installable: true,
srcs: [
// From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS
@@ -672,6 +673,7 @@
// ============================================================
java_library {
name: "ext",
+ installable: true,
no_framework_libs: true,
static_libs: [
"libphonenumber-platform",
@@ -1050,6 +1052,24 @@
" -showAnnotation android.annotation.TestApi",
}
+droiddoc {
+ name: "hiddenapi-mappings",
+ defaults: ["framework-docs-default"],
+ arg_files: [
+ "core/res/AndroidManifest.xml",
+ ":api-version-xml",
+ "core/java/overview.html",
+ ":current-support-api",
+ ],
+ dex_mapping_filename: "dex-mapping.txt",
+ args: framework_docs_args +
+ " -referenceonly" +
+ " -nodocs" +
+ " -showUnannotated" +
+ " -showAnnotation android.annotation.SystemApi" +
+ " -showAnnotation android.annotation.TestApi",
+}
+
filegroup {
name: "apache-http-stubs-sources",
srcs: [
diff --git a/api/current.txt b/api/current.txt
index 1ae46d5..9ffd50f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -40832,9 +40832,13 @@
method public java.lang.String getIccAuthentication(int, int, java.lang.String);
method public java.lang.String getImei();
method public java.lang.String getImei(int);
+ method public java.lang.String getTypeAllocationCode();
+ method public java.lang.String getTypeAllocationCode(int);
method public java.lang.String getLine1Number();
method public java.lang.String getMeid();
method public java.lang.String getMeid(int);
+ method public java.lang.String getManufacturerCode();
+ method public java.lang.String getManufacturerCode(int);
method public java.lang.String getMmsUAProfUrl();
method public java.lang.String getMmsUserAgent();
method public java.lang.String getNai();
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 5652d6d..a81d16a6 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -536,6 +536,20 @@
}
/**
+ * Resolves a transaction code to a human readable name.
+ *
+ * <p>Default implementation is a stub that returns null.
+ * <p>AIDL generated code will return the original method name.
+ *
+ * @param transactionCode The code to resolve.
+ * @return A human readable name.
+ * @hide
+ */
+ public @Nullable String getTransactionName(int transactionCode) {
+ return null;
+ }
+
+ /**
* Implemented to call the more convenient version
* {@link #dump(FileDescriptor, PrintWriter, String[])}.
*/
@@ -592,7 +606,7 @@
/**
* Print the object's state into the given stream.
- *
+ *
* @param fd The raw file descriptor that the dump is being sent to.
* @param fout The file to which you should dump your state. This will be
* closed for you after you return.
diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java
index 84c2e83..5718d99 100644
--- a/core/java/android/util/Half.java
+++ b/core/java/android/util/Half.java
@@ -20,8 +20,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import sun.misc.FloatingDecimal;
-
/**
* <p>The {@code Half} class is a wrapper and a utility class to manipulate half-precision 16-bit
* <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a>
@@ -1026,7 +1024,7 @@
* half-precision float value
*/
public static @HalfFloat short parseHalf(@NonNull String s) throws NumberFormatException {
- return toHalf(FloatingDecimal.parseFloat(s));
+ return toHalf(Float.parseFloat(s));
}
/**
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index 3617aa7..5a74ec0 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -18,9 +18,11 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import java.util.Arrays;
+
import libcore.util.EmptyArray;
+import java.util.Arrays;
+
/**
* Implements a growing array of int primitives.
*
@@ -102,7 +104,7 @@
ensureCapacity(1);
int rightSegment = mSize - index;
mSize++;
- checkBounds(index);
+ ArrayUtils.checkBounds(mSize, index);
if (rightSegment != 0) {
// Move by 1 all values from the right of 'index'
@@ -175,7 +177,7 @@
* Returns the value at the specified position in this array.
*/
public int get(int index) {
- checkBounds(index);
+ ArrayUtils.checkBounds(mSize, index);
return mValues[index];
}
@@ -183,7 +185,7 @@
* Sets the value at the specified position in this array.
*/
public void set(int index, int value) {
- checkBounds(index);
+ ArrayUtils.checkBounds(mSize, index);
mValues[index] = value;
}
@@ -205,7 +207,7 @@
* Removes the value at the specified index from this array.
*/
public void remove(int index) {
- checkBounds(index);
+ ArrayUtils.checkBounds(mSize, index);
System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1);
mSize--;
}
@@ -223,10 +225,4 @@
public int[] toArray() {
return Arrays.copyOf(mValues, mSize);
}
-
- private void checkBounds(int index) {
- if (index < 0 || mSize <= index) {
- throw new ArrayIndexOutOfBoundsException(mSize, index);
- }
- }
}
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
index 9b0489c..9ddb0e2 100644
--- a/core/java/android/util/LongArray.java
+++ b/core/java/android/util/LongArray.java
@@ -18,9 +18,11 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import java.util.Arrays;
+
import libcore.util.EmptyArray;
+import java.util.Arrays;
+
/**
* Implements a growing array of long primitives.
*
@@ -102,7 +104,7 @@
ensureCapacity(1);
int rightSegment = mSize - index;
mSize++;
- checkBounds(index);
+ ArrayUtils.checkBounds(mSize, index);
if (rightSegment != 0) {
// Move by 1 all values from the right of 'index'
@@ -162,7 +164,7 @@
* Returns the value at the specified position in this array.
*/
public long get(int index) {
- checkBounds(index);
+ ArrayUtils.checkBounds(mSize, index);
return mValues[index];
}
@@ -170,7 +172,7 @@
* Sets the value at the specified position in this array.
*/
public void set(int index, long value) {
- checkBounds(index);
+ ArrayUtils.checkBounds(mSize, index);
mValues[index] = value;
}
@@ -192,7 +194,7 @@
* Removes the value at the specified index from this array.
*/
public void remove(int index) {
- checkBounds(index);
+ ArrayUtils.checkBounds(mSize, index);
System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1);
mSize--;
}
@@ -210,10 +212,4 @@
public long[] toArray() {
return Arrays.copyOf(mValues, mSize);
}
-
- private void checkBounds(int index) {
- if (index < 0 || mSize <= index) {
- throw new ArrayIndexOutOfBoundsException(mSize, index);
- }
- }
}
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 41802cc..fb54e69 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -192,7 +192,7 @@
reader.finishLine();
}
} catch (NullPointerException|NumberFormatException e) {
- throw new ProtocolException("problem parsing stats", e);
+ throw protocolExceptionWithCause("problem parsing stats", e);
} finally {
IoUtils.closeQuietly(reader);
StrictMode.setThreadPolicy(savedPolicy);
@@ -242,7 +242,7 @@
reader.finishLine();
}
} catch (NullPointerException|NumberFormatException e) {
- throw new ProtocolException("problem parsing stats", e);
+ throw protocolExceptionWithCause("problem parsing stats", e);
} finally {
IoUtils.closeQuietly(reader);
StrictMode.setThreadPolicy(savedPolicy);
@@ -339,7 +339,7 @@
reader.finishLine();
}
} catch (NullPointerException|NumberFormatException e) {
- throw new ProtocolException("problem parsing idx " + idx, e);
+ throw protocolExceptionWithCause("problem parsing idx " + idx, e);
} finally {
IoUtils.closeQuietly(reader);
StrictMode.setThreadPolicy(savedPolicy);
@@ -376,4 +376,10 @@
@VisibleForTesting
public static native int nativeReadNetworkStatsDev(NetworkStats stats);
+
+ private static ProtocolException protocolExceptionWithCause(String message, Throwable cause) {
+ ProtocolException pe = new ProtocolException(message);
+ pe.initCause(cause);
+ return pe;
+ }
}
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index ea4575a..5bddd2f 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -16,9 +16,15 @@
package com.android.internal.os;
+import android.annotation.NonNull;
+import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.EventLog;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+import com.android.internal.util.Preconditions;
import dalvik.system.VMRuntime;
@@ -31,11 +37,14 @@
* @see IBinder
*/
public class BinderInternal {
+ private static final String TAG = "BinderInternal";
static WeakReference<GcWatcher> sGcWatcher
= new WeakReference<GcWatcher>(new GcWatcher());
static ArrayList<Runnable> sGcWatchers = new ArrayList<>();
static Runnable[] sTmpWatchers = new Runnable[1];
static long sLastGcTime;
+ static final BinderProxyLimitListenerDelegate sBinderProxyLimitListenerDelegate =
+ new BinderProxyLimitListenerDelegate();
static final class GcWatcher {
@Override
@@ -106,4 +115,96 @@
static void forceBinderGc() {
forceGc("Binder");
}
+
+ /**
+ * Enable/disable Binder Proxy Instance Counting by Uid. While enabled, the set callback will
+ * be called if this process holds too many Binder Proxies on behalf of a Uid.
+ * @param enabled true to enable counting, false to disable
+ */
+ public static final native void nSetBinderProxyCountEnabled(boolean enabled);
+
+ /**
+ * Get the current number of Binder Proxies held for each uid.
+ * @return SparseIntArray mapping uids to the number of Binder Proxies currently held
+ */
+ public static final native SparseIntArray nGetBinderProxyPerUidCounts();
+
+ /**
+ * Get the current number of Binder Proxies held for an individual uid.
+ * @param uid Requested uid for Binder Proxy count
+ * @return int with the number of Binder proxies held for a uid
+ */
+ public static final native int nGetBinderProxyCount(int uid);
+
+ /**
+ * Set the Binder Proxy watermarks. Default high watermark = 2500. Default low watermark = 2000
+ * @param high The limit at which the BinderProxyListener callback will be called.
+ * @param low The threshold a binder count must drop below before the callback
+ * can be called again. (This is to avoid many repeated calls to the
+ * callback in a brief period of time)
+ */
+ public static final native void nSetBinderProxyCountWatermarks(int high, int low);
+
+ /**
+ * Interface for callback invocation when the Binder Proxy limit is reached. onLimitReached will
+ * be called with the uid of the app causing too many Binder Proxies
+ */
+ public interface BinderProxyLimitListener {
+ public void onLimitReached(int uid);
+ }
+
+ /**
+ * Callback used by native code to trigger a callback in java code. The callback will be
+ * triggered when too many binder proxies from a uid hits the allowed limit.
+ * @param uid The uid of the bad behaving app sending too many binders
+ */
+ public static void binderProxyLimitCallbackFromNative(int uid) {
+ sBinderProxyLimitListenerDelegate.notifyClient(uid);
+ }
+
+ /**
+ * Set a callback to be triggered when a uid's Binder Proxy limit is reached for this process.
+ * @param listener OnLimitReached of listener will be called in the thread provided by handler
+ * @param handler must not be null, callback will be posted through the handler;
+ *
+ */
+ public static void setBinderProxyCountCallback(BinderProxyLimitListener listener,
+ @NonNull Handler handler) {
+ Preconditions.checkNotNull(handler,
+ "Must provide NonNull Handler to setBinderProxyCountCallback when setting "
+ + "BinderProxyLimitListener");
+ sBinderProxyLimitListenerDelegate.setListener(listener, handler);
+ }
+
+ /**
+ * Clear the Binder Proxy callback
+ */
+ public static void clearBinderProxyCountCallback() {
+ sBinderProxyLimitListenerDelegate.setListener(null, null);
+ }
+
+ static private class BinderProxyLimitListenerDelegate {
+ private BinderProxyLimitListener mBinderProxyLimitListener;
+ private Handler mHandler;
+
+ void setListener(BinderProxyLimitListener listener, Handler handler) {
+ synchronized (this) {
+ mBinderProxyLimitListener = listener;
+ mHandler = handler;
+ }
+ }
+
+ void notifyClient(final int uid) {
+ synchronized (this) {
+ if (mBinderProxyLimitListener != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mBinderProxyLimitListener.onLimitReached(uid);
+ }
+ });
+ }
+ }
+ }
+ }
}
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 91bc681..534f3b6 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -587,4 +587,17 @@
public static @NonNull String[] defeatNullable(@Nullable String[] val) {
return (val != null) ? val : EmptyArray.STRING;
}
+
+ /**
+ * Throws {@link ArrayIndexOutOfBoundsException} if the index is out of bounds.
+ *
+ * @param len length of the array. Must be non-negative
+ * @param index the index to check
+ * @throws ArrayIndexOutOfBoundsException if the {@code index} is out of bounds of the array
+ */
+ public static void checkBounds(int len, int index) {
+ if (index < 0 || len <= index) {
+ throw new ArrayIndexOutOfBoundsException("length=" + len + "; index=" + index);
+ }
+ }
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index a040940..aa68e75 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -33,6 +33,7 @@
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
+#include <binder/BpBinder.h>
#include <binder/ProcessState.h>
#include <cutils/atomic.h>
#include <log/log.h>
@@ -81,9 +82,17 @@
// Class state.
jclass mClass;
jmethodID mForceGc;
+ jmethodID mProxyLimitCallback;
} gBinderInternalOffsets;
+static struct sparseintarray_offsets_t
+{
+ jclass classObject;
+ jmethodID constructor;
+ jmethodID put;
+} gSparseIntArrayOffsets;
+
// ----------------------------------------------------------------------------
static struct error_offsets_t
@@ -993,6 +1002,43 @@
gCollectedAtRefs = gNumLocalRefsCreated + gNumDeathRefsCreated;
}
+static void android_os_BinderInternal_proxyLimitcallback(int uid)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
+ gBinderInternalOffsets.mProxyLimitCallback,
+ uid);
+}
+
+static void android_os_BinderInternal_setBinderProxyCountEnabled(JNIEnv* env, jobject clazz,
+ jboolean enable)
+{
+ BpBinder::setCountByUidEnabled((bool) enable);
+}
+
+static jobject android_os_BinderInternal_getBinderProxyPerUidCounts(JNIEnv* env, jclass clazz)
+{
+ Vector<uint32_t> uids, counts;
+ BpBinder::getCountByUid(uids, counts);
+ jobject sparseIntArray = env->NewObject(gSparseIntArrayOffsets.classObject,
+ gSparseIntArrayOffsets.constructor);
+ for (size_t i = 0; i < uids.size(); i++) {
+ env->CallVoidMethod(sparseIntArray, gSparseIntArrayOffsets.put,
+ static_cast<jint>(uids[i]), static_cast<jint>(counts[i]));
+ }
+ return sparseIntArray;
+}
+
+static jint android_os_BinderInternal_getBinderProxyCount(JNIEnv* env, jobject clazz, jint uid) {
+ return static_cast<jint>(BpBinder::getBinderProxyCount(static_cast<uint32_t>(uid)));
+}
+
+static void android_os_BinderInternal_setBinderProxyCountWatermarks(JNIEnv* env, jobject clazz,
+ jint high, jint low)
+{
+ BpBinder::setBinderProxyCountWatermarks(high, low);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gBinderInternalMethods[] = {
@@ -1001,7 +1047,11 @@
{ "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },
{ "disableBackgroundScheduling", "(Z)V", (void*)android_os_BinderInternal_disableBackgroundScheduling },
{ "setMaxThreads", "(I)V", (void*)android_os_BinderInternal_setMaxThreads },
- { "handleGc", "()V", (void*)android_os_BinderInternal_handleGc }
+ { "handleGc", "()V", (void*)android_os_BinderInternal_handleGc },
+ { "nSetBinderProxyCountEnabled", "(Z)V", (void*)android_os_BinderInternal_setBinderProxyCountEnabled },
+ { "nGetBinderProxyPerUidCounts", "()Landroid/util/SparseIntArray;", (void*)android_os_BinderInternal_getBinderProxyPerUidCounts },
+ { "nGetBinderProxyCount", "(I)I", (void*)android_os_BinderInternal_getBinderProxyCount },
+ { "nSetBinderProxyCountWatermarks", "(II)V", (void*)android_os_BinderInternal_setBinderProxyCountWatermarks}
};
const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
@@ -1012,6 +1062,16 @@
gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc", "()V");
+ gBinderInternalOffsets.mProxyLimitCallback = GetStaticMethodIDOrDie(env, clazz, "binderProxyLimitCallbackFromNative", "(I)V");
+
+ jclass SparseIntArrayClass = FindClassOrDie(env, "android/util/SparseIntArray");
+ gSparseIntArrayOffsets.classObject = MakeGlobalRefOrDie(env, SparseIntArrayClass);
+ gSparseIntArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject,
+ "<init>", "()V");
+ gSparseIntArrayOffsets.put = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject, "put",
+ "(II)V");
+
+ BpBinder::setLimitCallback(android_os_BinderInternal_proxyLimitcallback);
return RegisterMethodsOrDie(
env, kBinderInternalPathName,
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index a97e79b..b990068 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -19,7 +19,12 @@
$(call all-java-files-under, src) \
$(call all-Iaidl-files-under, src) \
$(call all-java-files-under, DisabledTestApp/src) \
- $(call all-java-files-under, EnabledTestApp/src)
+ $(call all-java-files-under, EnabledTestApp/src) \
+ $(call all-java-files-under, BinderProxyCountingTestApp/src) \
+ $(call all-java-files-under, BinderProxyCountingTestService/src) \
+ $(call all-Iaidl-files-under, aidl)
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
LOCAL_DX_FLAGS := --core-library
LOCAL_JACK_FLAGS := --multi-dex native
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index c0a8acd..cfb2359 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -86,6 +86,7 @@
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+ <uses-permission android:name="android.permission.KILL_UID" />
<!-- location test permissions -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
new file mode 100644
index 0000000..c3af6bd
--- /dev/null
+++ b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
@@ -0,0 +1,28 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := BinderProxyCountingTestApp
+LOCAL_SDK_VERSION := current
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml b/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..a971730
--- /dev/null
+++ b/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.binderproxycountingtestapp">
+
+ <application>
+ <service android:name=".BpcTestAppCmdService"
+ android:exported="true"/>
+ </application>
+</manifest>
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java b/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
new file mode 100644
index 0000000..5aae1203
--- /dev/null
+++ b/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
@@ -0,0 +1,182 @@
+/*
+ * 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 com.android.frameworks.coretests.binderproxycountingtestapp;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.frameworks.coretests.aidl.IBinderProxyCountingService;
+import com.android.frameworks.coretests.aidl.IBpcTestAppCmdService;
+import com.android.frameworks.coretests.aidl.ITestRemoteCallback;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class BpcTestAppCmdService extends Service {
+ private static final String TAG = BpcTestAppCmdService.class.getSimpleName();
+
+ private static final String TEST_SERVICE_PKG =
+ "com.android.frameworks.coretests.binderproxycountingtestservice";
+ private static final String TEST_SERVICE_CLASS =
+ TEST_SERVICE_PKG + ".BinderProxyCountingService";
+ private static final int BIND_SERVICE_TIMEOUT_SEC = 5;
+
+ private static ServiceConnection mServiceConnection;
+ private static IBinderProxyCountingService mBpcService;
+
+ private IBpcTestAppCmdService.Stub mBinder = new IBpcTestAppCmdService.Stub() {
+
+ private ArrayList<BroadcastReceiver> mBrList = new ArrayList();
+ private ArrayList<ITestRemoteCallback> mTrcList = new ArrayList();
+
+ @Override
+ public void createSystemBinders(int count) {
+ int i = 0;
+ while (i++ < count) {
+ BroadcastReceiver br = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+
+ }
+ };
+ IntentFilter filt = new IntentFilter(Intent.ACTION_POWER_DISCONNECTED);
+ synchronized (mBrList) {
+ mBrList.add(br);
+ }
+ registerReceiver(br, filt);
+ }
+ }
+
+ @Override
+ public void releaseSystemBinders(int count) {
+ int i = 0;
+ while (i++ < count) {
+ BroadcastReceiver br;
+ synchronized (mBrList) {
+ br = mBrList.remove(0);
+ }
+ unregisterReceiver(br);
+ }
+ }
+
+ @Override
+ public void createTestBinders(int count) {
+ int i = 0;
+ while (i++ < count) {
+ ITestRemoteCallback cb = new ITestRemoteCallback.Stub() {};
+ synchronized (mTrcList) {
+ mTrcList.add(cb);
+ }
+ try {
+ mBpcService.registerCallback(cb);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException caught! " + e);
+ }
+ }
+ }
+
+ @Override
+ public void releaseTestBinders(int count) {
+ int i = 0;
+ while (i++ < count) {
+
+ ITestRemoteCallback cb;
+ synchronized (mTrcList) {
+ cb = mTrcList.remove(0);
+ }
+ try {
+ mBpcService.unregisterCallback(cb);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException caught! " + e);
+ }
+ }
+ }
+
+ @Override
+ public void releaseAllBinders() {
+ synchronized (mBrList) {
+ while (mBrList.size() > 0) {
+ unregisterReceiver(mBrList.remove(0));
+ }
+ }
+ synchronized (mTrcList) {
+ while (mTrcList.size() > 0) {
+ try {
+ mBpcService.unregisterCallback(mTrcList.remove(0));
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException caught! " + e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public String bindToTestService() {
+ try {
+ final CountDownLatch bindLatch = new CountDownLatch(1);
+ mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.i(TAG, "Service connected");
+ mBpcService = IBinderProxyCountingService.Stub.asInterface(service);
+ bindLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.i(TAG, "Service disconnected");
+ }
+ };
+ final Intent intent = new Intent()
+ .setComponent(new ComponentName(TEST_SERVICE_PKG, TEST_SERVICE_CLASS));
+ bindService(intent, mServiceConnection,
+ Context.BIND_AUTO_CREATE
+ | Context.BIND_ALLOW_OOM_MANAGEMENT
+ | Context.BIND_NOT_FOREGROUND);
+ if (!bindLatch.await(BIND_SERVICE_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ throw new RuntimeException("Failed to bind to " + TEST_SERVICE_CLASS);
+ }
+ } catch (Exception e) {
+ unbindFromTestService();
+ Log.e(TAG, e.toString());
+ return e.toString();
+ }
+ return null;
+ }
+
+ @Override
+ public void unbindFromTestService() {
+ if (mBpcService != null) {
+ unbindService(mServiceConnection);
+ }
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+}
\ No newline at end of file
diff --git a/core/tests/coretests/BinderProxyCountingTestService/Android.mk b/core/tests/coretests/BinderProxyCountingTestService/Android.mk
new file mode 100644
index 0000000..34016ed
--- /dev/null
+++ b/core/tests/coretests/BinderProxyCountingTestService/Android.mk
@@ -0,0 +1,28 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := BinderProxyCountingTestService
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/core/tests/coretests/BinderProxyCountingTestService/AndroidManifest.xml b/core/tests/coretests/BinderProxyCountingTestService/AndroidManifest.xml
new file mode 100644
index 0000000..777bd20
--- /dev/null
+++ b/core/tests/coretests/BinderProxyCountingTestService/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.binderproxycountingtestservice">
+
+ <application>
+ <service android:name=".BpcTestServiceCmdService"
+ android:exported="true" />
+ <service android:name=".BinderProxyCountingService"
+ android:exported="true" />
+ </application>
+</manifest>
diff --git a/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BinderProxyCountingService.java b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BinderProxyCountingService.java
new file mode 100644
index 0000000..41b4c69
--- /dev/null
+++ b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BinderProxyCountingService.java
@@ -0,0 +1,53 @@
+/*
+ * 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 com.android.frameworks.coretests.binderproxycountingtestservice;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteCallbackList;
+
+import com.android.frameworks.coretests.aidl.IBinderProxyCountingService;
+import com.android.frameworks.coretests.aidl.ITestRemoteCallback;
+
+public class BinderProxyCountingService extends Service {
+ private static final String TAG = BinderProxyCountingService.class.getSimpleName();
+
+ private IBinderProxyCountingService.Stub mBinder = new IBinderProxyCountingService.Stub() {
+
+ final RemoteCallbackList<ITestRemoteCallback> mTestCallbacks = new RemoteCallbackList<>();
+
+ @Override
+ public void registerCallback(ITestRemoteCallback callback) {
+ synchronized (this) {
+ mTestCallbacks.register(callback);
+ }
+ }
+
+ @Override
+ public void unregisterCallback(ITestRemoteCallback callback) {
+ synchronized (this) {
+ mTestCallbacks.unregister(callback);
+ }
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+}
\ No newline at end of file
diff --git a/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
new file mode 100644
index 0000000..6bed2a2
--- /dev/null
+++ b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
@@ -0,0 +1,101 @@
+/*
+ * 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 com.android.frameworks.coretests.binderproxycountingtestservice;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Debug;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.frameworks.coretests.aidl.IBpcCallbackObserver;
+import com.android.frameworks.coretests.aidl.IBpcTestServiceCmdService;
+import com.android.internal.os.BinderInternal;
+
+public class BpcTestServiceCmdService extends Service {
+ private static final String TAG = BpcTestServiceCmdService.class.getSimpleName();
+
+ //ServiceThread mHandlerThread;
+ Handler mHandler;
+ HandlerThread mHandlerThread;
+
+ private IBpcTestServiceCmdService.Stub mBinder = new IBpcTestServiceCmdService.Stub() {
+ IBpcCallbackObserver mCallbackObserver;
+
+ @Override
+ public void forceGc() {
+ int gcCount = Integer.parseInt(Debug.getRuntimeStat("art.gc.gc-count"));
+ int i = 20;
+ while (gcCount == Integer.parseInt(Debug.getRuntimeStat("art.gc.gc-count")) && i > 0) {
+ System.gc();
+ System.runFinalization();
+ i--;
+ }
+ }
+
+ @Override
+ public int getBinderProxyCount(int uid) {
+ return BinderInternal.nGetBinderProxyCount(uid);
+ }
+
+ @Override
+ public void setBinderProxyWatermarks(int high, int low) {
+ BinderInternal.nSetBinderProxyCountWatermarks(high, low);
+ }
+
+ @Override
+ public void enableBinderProxyLimit(boolean enable) {
+ BinderInternal.nSetBinderProxyCountEnabled(enable);
+ }
+
+ @Override
+ public void setBinderProxyCountCallback(IBpcCallbackObserver observer) {
+ if (observer != null) {
+ BinderInternal.setBinderProxyCountCallback(
+ new BinderInternal.BinderProxyLimitListener() {
+ @Override
+ public void onLimitReached(int uid) {
+ try {
+ synchronized (observer) {
+ observer.onCallback(uid);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+ }, mHandler);
+ } else {
+ BinderInternal.clearBinderProxyCountCallback();
+ }
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ @Override
+ public void onCreate()
+ {
+ mHandlerThread = new HandlerThread("BinderProxyCountingServiceThread");
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ }
+}
\ No newline at end of file
diff --git a/core/tests/coretests/aidl/Android.mk b/core/tests/coretests/aidl/Android.mk
new file mode 100644
index 0000000..86e36b6
--- /dev/null
+++ b/core/tests/coretests/aidl/Android.mk
@@ -0,0 +1,22 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-subdir-Iaidl-files)
+LOCAL_MODULE := coretests-aidl
+include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBinderProxyCountingService.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBinderProxyCountingService.aidl
new file mode 100644
index 0000000..a69b0c5
--- /dev/null
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBinderProxyCountingService.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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 com.android.frameworks.coretests.aidl;
+import com.android.frameworks.coretests.aidl.ITestRemoteCallback;
+
+interface IBinderProxyCountingService {
+ void registerCallback(in ITestRemoteCallback callback);
+ void unregisterCallback(in ITestRemoteCallback callback);
+}
\ No newline at end of file
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
new file mode 100644
index 0000000..c4ebd56
--- /dev/null
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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 com.android.frameworks.coretests.aidl;
+
+interface IBpcCallbackObserver {
+ void onCallback(int uid);
+}
\ No newline at end of file
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestAppCmdService.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestAppCmdService.aidl
new file mode 100644
index 0000000..86a0aa0f
--- /dev/null
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestAppCmdService.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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 com.android.frameworks.coretests.aidl;
+
+interface IBpcTestAppCmdService {
+ void createSystemBinders(int count);
+ void releaseSystemBinders(int count);
+
+ void createTestBinders(int count);
+ void releaseTestBinders(int count);
+
+ void releaseAllBinders();
+
+ String bindToTestService();
+ void unbindFromTestService();
+}
\ No newline at end of file
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
new file mode 100644
index 0000000..abdab41
--- /dev/null
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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 com.android.frameworks.coretests.aidl;
+import com.android.frameworks.coretests.aidl.IBpcCallbackObserver;
+
+interface IBpcTestServiceCmdService {
+ void forceGc();
+ int getBinderProxyCount(int uid);
+ void setBinderProxyWatermarks(int high, int low);
+ void enableBinderProxyLimit(boolean enable);
+ void setBinderProxyCountCallback(IBpcCallbackObserver observer);
+}
\ No newline at end of file
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ITestRemoteCallback.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ITestRemoteCallback.aidl
new file mode 100644
index 0000000..36bdb6c
--- /dev/null
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ITestRemoteCallback.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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 com.android.frameworks.coretests.aidl;
+
+interface ITestRemoteCallback {
+}
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
new file mode 100644
index 0000000..6cdb35ab
--- /dev/null
+++ b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.os;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+
+import com.android.frameworks.coretests.aidl.IBpcCallbackObserver;
+import com.android.frameworks.coretests.aidl.IBpcTestAppCmdService;
+import com.android.frameworks.coretests.aidl.IBpcTestServiceCmdService;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Tests for verifying the Binder Proxy Counting and Limiting.
+ *
+ * To manually build and install relevant test apps
+ *
+ * Build:
+ * mmma frameworks/base/core/tests/coretests/BinderProxyCountingTestApp
+ * mmma frameworks/base/core/tests/coretests/BinderProxyCountingTestService
+ * Install:
+ * adb install -r \
+ * ${ANDROID_PRODUCT_OUT}/data/app/BinderProxyCountingTestApp/BinderProxyCountingTestApp.apk
+ * adb install -r \
+ * ${ANDROID_PRODUCT_OUT}/data/app/BinderProxyCountingTestService/BinderProxyCountingTestService.apk
+ *
+ * To run the tests, use
+ *
+ * Build: m FrameworksCoreTests
+ * Install: adb install -r \
+ * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
+ * Run: adb shell am instrument -e class android.os.BinderProxyCountingTest -w \
+ * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ *
+ * or
+ *
+ * bit FrameworksCoreTests:android.os.BinderProxyCountingTest
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class BinderProxyCountingTest {
+ private static final String TAG = BinderProxyCountingTest.class.getSimpleName();
+
+ private static final String TEST_APP_PKG =
+ "com.android.frameworks.coretests.binderproxycountingtestapp";
+ private static final String TEST_APP_CMD_SERVICE = TEST_APP_PKG + ".BpcTestAppCmdService";
+ private static final String TEST_SERVICE_PKG =
+ "com.android.frameworks.coretests.binderproxycountingtestservice";
+ private static final String TEST_SERVICE_CMD_SERVICE =
+ TEST_SERVICE_PKG + ".BpcTestServiceCmdService";
+
+ private static final int BIND_SERVICE_TIMEOUT_SEC = 5;
+ private static final int TOO_MANY_BINDERS_TIMEOUT_SEC = 2;
+
+ // Keep in sync with sBinderProxyCountLimit in BpBinder.cpp
+ private static final int BINDER_PROXY_LIMIT = 2500;
+
+ private static Context sContext;
+ private static UiDevice sUiDevice;
+
+ private static ServiceConnection sTestAppConnection;
+ private static ServiceConnection sTestServiceConnection;
+ private static IBpcTestAppCmdService sBpcTestAppCmdService;
+ private static IBpcTestServiceCmdService sBpcTestServiceCmdService;
+ private static final Intent sTestAppIntent = new Intent()
+ .setComponent(new ComponentName(TEST_APP_PKG, TEST_APP_CMD_SERVICE));
+ private static final Intent sTestServiceIntent = new Intent()
+ .setComponent(new ComponentName(TEST_SERVICE_PKG, TEST_SERVICE_CMD_SERVICE));
+ private static final Consumer<IBinder> sTestAppConsumer = (service) -> {
+ sBpcTestAppCmdService = IBpcTestAppCmdService.Stub.asInterface(service);
+ };
+ private static final Consumer<IBinder> sTestServiceConsumer = (service) -> {
+ sBpcTestServiceCmdService = IBpcTestServiceCmdService.Stub.asInterface(service);
+ };
+ private static int sTestPkgUid;
+
+ /**
+ * Setup any common data for the upcoming tests.
+ */
+ @BeforeClass
+ public static void setUpOnce() throws Exception {
+ sContext = InstrumentationRegistry.getContext();
+ sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_APP_PKG, 0);
+ ((ActivityManager) sContext.getSystemService(Context.ACTIVITY_SERVICE)).killUid(sTestPkgUid,
+ "Wiping Test Package");
+
+ sUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ }
+
+ private ServiceConnection bindService(final Consumer<IBinder> consumer, Intent intent)
+ throws Exception {
+ final CountDownLatch bindLatch = new CountDownLatch(1);
+ ServiceConnection connection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.i(TAG, "Service connected");
+ consumer.accept(service);
+ bindLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.i(TAG, "Service disconnected");
+ }
+ };
+ sContext.bindService(intent, connection,
+ Context.BIND_AUTO_CREATE
+ | Context.BIND_ALLOW_OOM_MANAGEMENT
+ | Context.BIND_NOT_FOREGROUND);
+ if (!bindLatch.await(BIND_SERVICE_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for the service to bind in " + sTestPkgUid);
+ }
+ return connection;
+ }
+
+
+ private void unbindService(ServiceConnection service) {
+ if (service != null) {
+ sContext.unbindService(service);
+ }
+ }
+
+ private void bindTestAppToTestService() throws Exception {
+ if (sBpcTestAppCmdService != null) {
+ String errorMessage = sBpcTestAppCmdService.bindToTestService();
+ if (errorMessage != null) {
+ fail(errorMessage);
+ }
+ }
+ }
+
+ private void unbindTestAppFromTestService() throws Exception {
+ if (sBpcTestAppCmdService != null) {
+ sBpcTestAppCmdService.unbindFromTestService();
+ }
+ }
+
+ private CountDownLatch createBinderLimitLatch() throws RemoteException {
+ final CountDownLatch latch = new CountDownLatch(1);
+ sBpcTestServiceCmdService.setBinderProxyCountCallback(
+ new IBpcCallbackObserver.Stub() {
+ @Override
+ public void onCallback(int uid) {
+ if (uid == sTestPkgUid) {
+ latch.countDown();
+ }
+ }
+ });
+ return latch;
+ }
+
+ /**
+ * Get the Binder Proxy count held by SYSTEM for a given uid
+ */
+ private int getSystemBinderCount(int uid) throws Exception {
+ return Integer.parseInt(sUiDevice.executeShellCommand(
+ "dumpsys activity binder-proxies " + uid).trim());
+ }
+
+ @Test
+ public void testBinderProxyCount() throws Exception {
+ // Arbitrary list of Binder create and release
+ // Should cumulatively equal 0 and must never add up past the binder limit at any point
+ int[] testValues = {223, -103, -13, 25, 90, -222};
+ try {
+ sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
+ // Get the baseline of binders naturally held by the test Package
+ int expectedBinderCount = getSystemBinderCount(sTestPkgUid);
+
+ for (int testValue : testValues) {
+ if (testValue > 0) {
+ sBpcTestAppCmdService.createSystemBinders(testValue);
+ } else {
+ sBpcTestAppCmdService.releaseSystemBinders(-testValue);
+ }
+ expectedBinderCount += testValue;
+ int currentBinderCount = getSystemBinderCount(sTestPkgUid);
+ assertEquals("Current Binder Count (" + currentBinderCount
+ + ") does not equal expected Binder Count (" + expectedBinderCount
+ + ")", expectedBinderCount, currentBinderCount);
+ }
+ } finally {
+ unbindService(sTestAppConnection);
+ }
+ }
+
+ @Test
+ public void testBinderProxyLimitBoundary() throws Exception {
+ final int binderProxyLimit = 2000;
+ final int rearmThreshold = 1800;
+ try {
+ sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
+ sTestServiceConnection = bindService(sTestServiceConsumer, sTestServiceIntent);
+ bindTestAppToTestService();
+ sBpcTestServiceCmdService.enableBinderProxyLimit(true);
+
+ sBpcTestServiceCmdService.forceGc();
+ // Get the baseline of binders naturally held by the test Package
+ int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+
+ final CountDownLatch binderLimitLatch = createBinderLimitLatch();
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
+
+ // Create Binder Proxies up to the limit
+ sBpcTestAppCmdService.createTestBinders(binderProxyLimit - baseBinderCount);
+ if (binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ + " when proxy limit should not have been reached");
+ }
+
+ // Create one more Binder to cross the limit
+ sBpcTestAppCmdService.createTestBinders(1);
+ if (!binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
+ }
+
+ sBpcTestAppCmdService.releaseAllBinders();
+ } finally {
+ unbindTestAppFromTestService();
+ unbindService(sTestAppConnection);
+ unbindService(sTestServiceConnection);
+ }
+ }
+
+ @Test
+ public void testSetBinderProxyLimit() throws Exception {
+ int[] testLimits = {1000, 222, 800};
+ try {
+ sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
+ sTestServiceConnection = bindService(sTestServiceConsumer, sTestServiceIntent);
+ bindTestAppToTestService();
+ sBpcTestServiceCmdService.enableBinderProxyLimit(true);
+
+ sBpcTestServiceCmdService.forceGc();
+ int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+ for (int testLimit : testLimits) {
+ final CountDownLatch binderLimitLatch = createBinderLimitLatch();
+ // Change the BinderProxyLimit
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(testLimit, baseBinderCount + 10);
+ // Exceed the new Binder Proxy Limit
+ sBpcTestAppCmdService.createTestBinders(testLimit + 1);
+ if (!binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
+ }
+
+ sBpcTestAppCmdService.releaseTestBinders(testLimit + 1);
+ sBpcTestServiceCmdService.forceGc();
+ }
+ } finally {
+ unbindTestAppFromTestService();
+ unbindService(sTestAppConnection);
+ unbindService(sTestServiceConnection);
+ }
+ }
+
+ @Test
+ public void testRearmCallbackThreshold() throws Exception {
+ final int binderProxyLimit = 2000;
+ final int exceedBinderProxyLimit = binderProxyLimit + 10;
+ final int rearmThreshold = 1800;
+ try {
+ sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
+ sTestServiceConnection = bindService(sTestServiceConsumer, sTestServiceIntent);
+ bindTestAppToTestService();
+ sBpcTestServiceCmdService.enableBinderProxyLimit(true);
+
+ sBpcTestServiceCmdService.forceGc();
+ final CountDownLatch firstBinderLimitLatch = createBinderLimitLatch();
+ sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
+ // Exceed the Binder Proxy Limit
+ sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit);
+ if (!firstBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
+ }
+
+ sBpcTestServiceCmdService.forceGc();
+ int currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+ // Drop to the threshold, this should not rearm the callback
+ sBpcTestAppCmdService.releaseTestBinders(currentBinderCount - rearmThreshold);
+
+ sBpcTestServiceCmdService.forceGc();
+ currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+
+ final CountDownLatch secondBinderLimitLatch = createBinderLimitLatch();
+ // Exceed the Binder Proxy limit which should not cause a callback since there has
+ // been no rearm
+ sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - currentBinderCount);
+ if (secondBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+ + " when the callback has not been rearmed yet");
+ }
+
+ sBpcTestServiceCmdService.forceGc();
+ currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+ // Drop below the rearmThreshold to rearm the BinderProxyLimitCallback
+ sBpcTestAppCmdService.releaseTestBinders(currentBinderCount - rearmThreshold + 1);
+
+ sBpcTestServiceCmdService.forceGc();
+ currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+ // Exceed the Binder Proxy limit for the last time
+ sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - currentBinderCount);
+
+ if (!secondBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
+ }
+ sBpcTestAppCmdService.releaseTestBinders(currentBinderCount);
+ } finally {
+ unbindTestAppFromTestService();
+ unbindService(sTestAppConnection);
+ unbindService(sTestServiceConnection);
+ }
+ }
+
+ @Test
+ public void testKillBadBehavingApp() throws Exception {
+ final CountDownLatch binderDeathLatch = new CountDownLatch(1);
+ final int exceedBinderProxyLimit = BINDER_PROXY_LIMIT + 1;
+
+ try {
+ sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
+ sBpcTestAppCmdService.asBinder().linkToDeath(new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ Log.v(TAG, "BpcTestAppCmdService died!");
+ binderDeathLatch.countDown();
+ }
+ }, 0);
+ try {
+ // Exceed the Binder Proxy Limit emulating a bad behaving app
+ sBpcTestAppCmdService.createSystemBinders(exceedBinderProxyLimit);
+ } catch (DeadObjectException doe) {
+ // We are expecting the service to get killed mid call, so a DeadObjectException
+ // is not unexpected
+ }
+
+ if (!binderDeathLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ sBpcTestAppCmdService.releaseSystemBinders(exceedBinderProxyLimit);
+ fail("Timed out waiting for uid " + sTestPkgUid + " to die.");
+ }
+
+ } finally {
+ unbindService(sTestAppConnection);
+ }
+ }
+}
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 616558f..648fd35 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -135,8 +135,6 @@
gBenchmarkReporter.reset(new benchmark::ConsoleReporter());
} else if (!strcmp(format, "json")) {
gBenchmarkReporter.reset(new benchmark::JSONReporter());
- } else if (!strcmp(format, "csv")) {
- gBenchmarkReporter.reset(new benchmark::CSVReporter());
} else {
fprintf(stderr, "Unknown format '%s'", format);
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 851b78c..ecbcb40 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -27,7 +27,6 @@
import com.android.systemui.util.wakelock.WakeLock;
import java.util.Calendar;
-import java.util.GregorianCalendar;
/**
* The policy controlling doze.
@@ -139,7 +138,7 @@
}
private long roundToNextMinute(long timeInMillis) {
- Calendar calendar = GregorianCalendar.getInstance();
+ Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timeInMillis);
calendar.set(Calendar.MILLISECOND, 0);
calendar.set(Calendar.SECOND, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
old mode 100644
new mode 100755
index 2d2869d..5a6a1c2
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -251,12 +251,13 @@
entry = Pair.<String, String>create(packageAndClassName[0], null);
break;
case 2:
- if (packageAndClassName[1] != null
- && packageAndClassName[1].startsWith(".")) {
- entry = Pair.<String, String>create(
- packageAndClassName[0],
- packageAndClassName[0] + packageAndClassName[1]);
+ if (packageAndClassName[1] != null) {
+ entry = Pair.<String, String>create(packageAndClassName[0],
+ packageAndClassName[1].startsWith(".")
+ ? packageAndClassName[0] + packageAndClassName[1]
+ : packageAndClassName[1]);
}
+ break;
}
if (entry != null) {
sSettingsPackageAndClassNamePairList.add(entry);
diff --git a/services/Android.bp b/services/Android.bp
index d125adc..bea51be 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -2,6 +2,7 @@
// ============================================================
java_library {
name: "services",
+ installable: true,
dex_preopt: {
app_image: true,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1546ec1..02d5d26 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -380,6 +380,7 @@
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.BinderInternal;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
@@ -14366,6 +14367,23 @@
}
mStackSupervisor.resumeFocusedStackTopActivityLocked();
mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
+
+ BinderInternal.nSetBinderProxyCountEnabled(true);
+ BinderInternal.setBinderProxyCountCallback(
+ new BinderInternal.BinderProxyLimitListener() {
+ @Override
+ public void onLimitReached(int uid) {
+ Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
+ + Process.myUid());
+ if (uid == Process.SYSTEM_UID) {
+ Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
+ } else {
+ killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
+ "Too many Binders sent to SYSTEM");
+ }
+ }
+ }, mHandler);
+
traceLog.traceEnd(); // ActivityManagerStartApps
traceLog.traceEnd(); // PhaseActivityManagerReady
}
@@ -15134,6 +15152,19 @@
synchronized (this) {
dumpRecentsLocked(fd, pw, args, opti, true, dumpPackage);
}
+ } else if ("binder-proxies".equals(cmd)) {
+ if (opti >= args.length) {
+ dumpBinderProxiesCounts(pw, BinderInternal.nGetBinderProxyPerUidCounts(),
+ "Counts of Binder Proxies held by SYSTEM");
+ } else {
+ String uid = args[opti];
+ opti++;
+ // Ensure Binder Proxy Count is as up to date as possible
+ System.gc();
+ System.runFinalization();
+ System.gc();
+ pw.println(BinderInternal.nGetBinderProxyCount(Integer.parseInt(uid)));
+ }
} else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
String[] newArgs;
String name;
@@ -15663,6 +15694,34 @@
return printed;
}
+ boolean dumpBinderProxiesCounts(PrintWriter pw, SparseIntArray counts, String header) {
+ if(counts != null) {
+ pw.println(header);
+ for (int i = 0; i < counts.size(); i++) {
+ final int uid = counts.keyAt(i);
+ final int binderCount = counts.valueAt(i);
+ pw.print(" UID ");
+ pw.print(uid);
+ pw.print(", binder count = ");
+ pw.print(binderCount);
+ pw.print(", package(s)= ");
+ final String[] pkgNames = mContext.getPackageManager().getPackagesForUid(uid);
+ if (pkgNames != null) {
+ for (int j = 0; j < pkgNames.length; j++) {
+ pw.print(pkgNames[j]);
+ pw.print("; ");
+ }
+ } else {
+ pw.print("NO PACKAGE NAME FOUND");
+ }
+ pw.println();
+ }
+ pw.println();
+ return true;
+ }
+ return false;
+ }
+
void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage) {
boolean needSep = false;
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
index 5af3c29..cfcba3a 100644
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ b/services/net/java/android/net/netlink/NetlinkSocket.java
@@ -59,10 +59,9 @@
final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage";
final long IO_TIMEOUT = 300L;
- FileDescriptor fd;
+ final FileDescriptor fd = forProto(nlProto);
try {
- fd = forProto(nlProto);
connectToKernel(fd);
sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT);
final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT);
@@ -96,9 +95,9 @@
} catch (SocketException e) {
Log.e(TAG, errPrefix, e);
throw new ErrnoException(errPrefix, EIO, e);
+ } finally {
+ IoUtils.closeQuietly(fd);
}
-
- IoUtils.closeQuietly(fd);
}
public static FileDescriptor forProto(int nlProto) throws ErrnoException {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e0b465d..3bc7341 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1230,6 +1230,33 @@
}
/**
+ * Returns the Type Allocation Code from the IMEI. Return null if Type Allocation Code is not
+ * available.
+ */
+ public String getTypeAllocationCode() {
+ return getTypeAllocationCode(getSlotIndex());
+ }
+
+ /**
+ * Returns the Type Allocation Code from the IMEI. Return null if Type Allocation Code is not
+ * available.
+ *
+ * @param slotIndex of which Type Allocation Code is returned
+ */
+ public String getTypeAllocationCode(int slotIndex) {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) return null;
+
+ try {
+ return telephony.getTypeAllocationCodeForSlot(slotIndex);
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ return null;
+ }
+ }
+
+ /**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -1265,6 +1292,33 @@
}
/**
+ * Returns the Manufacturer Code from the MEID. Return null if Manufacturer Code is not
+ * available.
+ */
+ public String getManufacturerCode() {
+ return getManufacturerCode(getSlotIndex());
+ }
+
+ /**
+ * Returns the Manufacturer Code from the MEID. Return null if Manufacturer Code is not
+ * available.
+ *
+ * @param slotIndex of which Type Allocation Code is returned
+ */
+ public String getManufacturerCode(int slotIndex) {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) return null;
+
+ try {
+ return telephony.getManufacturerCodeForSlot(slotIndex);
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ return null;
+ }
+ }
+
+ /**
* Returns the Network Access Identifier (NAI). Return null if NAI is not available.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java
index d03c7e1..e158fa8 100644
--- a/telephony/java/android/telephony/ims/ImsExternalCallState.java
+++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java
@@ -87,6 +87,7 @@
mCallId = in.readInt();
ClassLoader classLoader = ImsExternalCallState.class.getClassLoader();
mAddress = in.readParcelable(classLoader);
+ mLocalAddress = in.readParcelable(classLoader);
mIsPullable = (in.readInt() != 0);
mCallState = in.readInt();
mCallType = in.readInt();
@@ -103,6 +104,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mCallId);
out.writeParcelable(mAddress, 0);
+ out.writeParcelable(mLocalAddress, 0);
out.writeInt(mIsPullable ? 1 : 0);
out.writeInt(mCallState);
out.writeInt(mCallType);
@@ -131,6 +133,11 @@
return mAddress;
}
+ /** @hide */
+ public Uri getLocalAddress() {
+ return mLocalAddress;
+ }
+
public boolean isCallPullable() {
return mIsPullable;
}
@@ -151,6 +158,7 @@
public String toString() {
return "ImsExternalCallState { mCallId = " + mCallId +
", mAddress = " + Log.pii(mAddress) +
+ ", mLocalAddress = " + Log.pii(mLocalAddress) +
", mIsPullable = " + mIsPullable +
", mCallState = " + mCallState +
", mCallType = " + mCallType +
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 3fd1d04..70354b2 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1198,6 +1198,13 @@
String getImeiForSlot(int slotIndex, String callingPackage);
/**
+ * Returns the Type Allocation Code from the IMEI for the given slot.
+ *
+ * @param slotIndex - Which slot to retrieve the Type Allocation Code from.
+ */
+ String getTypeAllocationCodeForSlot(int slotIndex);
+
+ /**
* Returns the MEID for the given slot.
*
* @param slotIndex - device slot.
@@ -1208,6 +1215,13 @@
String getMeidForSlot(int slotIndex, String callingPackage);
/**
+ * Returns the Manufacturer Code from the MEID for the given slot.
+ *
+ * @param slotIndex - Which slot to retrieve the Manufacturer Code from.
+ */
+ String getManufacturerCodeForSlot(int slotIndex);
+
+ /**
* Returns the device software version.
*
* @param slotIndex - device slot.
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 194b90e..d25b477 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -21,6 +21,7 @@
// Also contains the com.android.internal.util.Predicate[s] classes.
java_library {
name: "android.test.base",
+ installable: true,
srcs: ["src/**/*.java"],
@@ -42,6 +43,7 @@
// Also contains the com.android.internal.util.Predicate[s] classes.
java_library {
name: "legacy-test",
+ installable: true,
sdk_version: "current",
static_libs: ["android.test.base"],
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index d726dc4..d4ecd62 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -18,6 +18,7 @@
// ===================================
java_library {
name: "android.test.mock",
+ installable: true,
// Needs to be consistent with the repackaged version of this make target.
java_version: "1.8",
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index aaa29de..e605940 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -18,6 +18,7 @@
// =====================================
java_library {
name: "android.test.runner",
+ installable: true,
// Needs to be consistent with the repackaged version of this make target.
java_version: "1.8",