Merge "Adding new intent ACTION_SMS_MMS_DB_CREATED."
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 09343f1..70e81df 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -125,6 +125,8 @@
filterType = VolumeInfo.TYPE_PRIVATE;
} else if ("emulated".equals(filter)) {
filterType = VolumeInfo.TYPE_EMULATED;
+ } else if ("stub".equals(filter)) {
+ filterType = VolumeInfo.TYPE_STUB;
} else {
filterType = -1;
}
@@ -298,7 +300,7 @@
private static int showUsage() {
System.err.println("usage: sm list-disks [adoptable]");
- System.err.println(" sm list-volumes [public|private|emulated|all]");
+ System.err.println(" sm list-volumes [public|private|emulated|stub|all]");
System.err.println(" sm has-adoptable");
System.err.println(" sm get-primary-storage-uuid");
System.err.println(" sm set-force-adoptable [on|off|default]");
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index e492f88..591370f 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -225,10 +225,11 @@
}
}
- /**
- * Dump a histogram to the logcat. Used to diagnose abnormally large proxy maps.
- */
- private void dumpProxyInterfaceCounts() {
+ private InterfaceCount[] getSortedInterfaceCounts(int maxToReturn) {
+ if (maxToReturn < 0) {
+ throw new IllegalArgumentException("negative interface count");
+ }
+
Map<String, Integer> counts = new HashMap<>();
for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) {
if (a != null) {
@@ -258,13 +259,30 @@
}
Map.Entry<String, Integer>[] sorted = counts.entrySet().toArray(
new Map.Entry[counts.size()]);
+
Arrays.sort(sorted, (Map.Entry<String, Integer> a, Map.Entry<String, Integer> b)
-> b.getValue().compareTo(a.getValue()));
- Log.v(Binder.TAG, "BinderProxy descriptor histogram (top ten):");
- int printLength = Math.min(10, sorted.length);
- for (int i = 0; i < printLength; i++) {
- Log.v(Binder.TAG, " #" + (i + 1) + ": " + sorted[i].getKey() + " x"
- + sorted[i].getValue());
+
+ int returnCount = Math.min(maxToReturn, sorted.length);
+ InterfaceCount[] ifaceCounts = new InterfaceCount[returnCount];
+ for (int i = 0; i < returnCount; i++) {
+ ifaceCounts[i] = new InterfaceCount(sorted[i].getKey(), sorted[i].getValue());
+ }
+ return ifaceCounts;
+ }
+
+ static final int MAX_NUM_INTERFACES_TO_DUMP = 10;
+
+ /**
+ * Dump a histogram to the logcat. Used to diagnose abnormally large proxy maps.
+ */
+ private void dumpProxyInterfaceCounts() {
+ final InterfaceCount[] sorted = getSortedInterfaceCounts(MAX_NUM_INTERFACES_TO_DUMP);
+
+ Log.v(Binder.TAG, "BinderProxy descriptor histogram "
+ + "(top " + Integer.toString(MAX_NUM_INTERFACES_TO_DUMP) + "):");
+ for (int i = 0; i < sorted.length; i++) {
+ Log.v(Binder.TAG, " #" + (i + 1) + ": " + sorted[i]);
}
}
@@ -296,30 +314,57 @@
new ArrayList[MAIN_INDEX_SIZE];
}
- private static ProxyMap sProxyMap = new ProxyMap();
+ @GuardedBy("sProxyMap")
+ private static final ProxyMap sProxyMap = new ProxyMap();
/**
- * Dump proxy debug information.
- *
- * Note: this method is not thread-safe; callers must serialize with other
- * accesses to sProxyMap, in particular {@link #getInstance(long, long)}.
- *
- * @hide
- */
- private static void dumpProxyDebugInfo() {
+ * Simple pair-value class to store number of binder proxy interfaces live in this process.
+ */
+ public static final class InterfaceCount {
+ private final String mInterfaceName;
+ private final int mCount;
+
+ InterfaceCount(String interfaceName, int count) {
+ mInterfaceName = interfaceName;
+ mCount = count;
+ }
+
+ @Override
+ public String toString() {
+ return mInterfaceName + " x" + Integer.toString(mCount);
+ }
+ }
+
+ /**
+ * Get a sorted array with entries mapping proxy interface names to the number
+ * of live proxies with those names.
+ *
+ * @param num maximum number of proxy interface counts to return. Use
+ * Integer.MAX_VALUE to retrieve all
+ * @hide
+ */
+ public static InterfaceCount[] getSortedInterfaceCounts(int num) {
+ synchronized (sProxyMap) {
+ return sProxyMap.getSortedInterfaceCounts(num);
+ }
+ }
+
+ /**
+ * Dump proxy debug information.
+ *
+ * @hide
+ */
+ public static void dumpProxyDebugInfo() {
if (Build.IS_DEBUGGABLE) {
- sProxyMap.dumpProxyInterfaceCounts();
- // Note that we don't call dumpPerUidProxyCounts(); this is because this
- // method may be called as part of the uid limit being hit, and calling
- // back into the UID tracking code would cause us to try to acquire a mutex
- // that is held during that callback.
+ synchronized (sProxyMap) {
+ sProxyMap.dumpProxyInterfaceCounts();
+ sProxyMap.dumpPerUidProxyCounts();
+ }
}
}
/**
* Return a BinderProxy for IBinder.
- * This method is thread-hostile! The (native) caller serializes getInstance() calls using
- * gProxyLock.
* If we previously returned a BinderProxy bp for the same iBinder, and bp is still
* in use, then we return the same bp.
*
@@ -331,21 +376,23 @@
*/
private static BinderProxy getInstance(long nativeData, long iBinder) {
BinderProxy result;
- try {
- result = sProxyMap.get(iBinder);
- if (result != null) {
- return result;
+ synchronized (sProxyMap) {
+ try {
+ result = sProxyMap.get(iBinder);
+ if (result != null) {
+ return result;
+ }
+ result = new BinderProxy(nativeData);
+ } catch (Throwable e) {
+ // We're throwing an exception (probably OOME); don't drop nativeData.
+ NativeAllocationRegistry.applyFreeFunction(NoImagePreloadHolder.sNativeFinalizer,
+ nativeData);
+ throw e;
}
- result = new BinderProxy(nativeData);
- } catch (Throwable e) {
- // We're throwing an exception (probably OOME); don't drop nativeData.
- NativeAllocationRegistry.applyFreeFunction(NoImagePreloadHolder.sNativeFinalizer,
- nativeData);
- throw e;
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(result, nativeData);
+ // The registry now owns nativeData, even if registration threw an exception.
+ sProxyMap.set(iBinder, result);
}
- NoImagePreloadHolder.sRegistry.registerNativeAllocation(result, nativeData);
- // The registry now owns nativeData, even if registration threw an exception.
- sProxyMap.set(iBinder, result);
return result;
}
@@ -526,12 +573,11 @@
}
}
- private static final void sendDeathNotice(DeathRecipient recipient) {
+ private static void sendDeathNotice(DeathRecipient recipient) {
if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);
try {
recipient.binderDied();
- }
- catch (RuntimeException exc) {
+ } catch (RuntimeException exc) {
Log.w("BinderNative", "Uncaught exception from death notification",
exc);
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index d9eb775..d072d02 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -774,7 +774,7 @@
try {
for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
if (vol.path != null && FileUtils.contains(vol.path, pathString)
- && vol.type != VolumeInfo.TYPE_PUBLIC) {
+ && vol.type != VolumeInfo.TYPE_PUBLIC && vol.type != VolumeInfo.TYPE_STUB) {
// TODO: verify that emulated adopted devices have UUID of
// underlying volume
try {
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index afd38369..a0c7f75 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -84,6 +84,7 @@
public static final int TYPE_EMULATED = IVold.VOLUME_TYPE_EMULATED;
public static final int TYPE_ASEC = IVold.VOLUME_TYPE_ASEC;
public static final int TYPE_OBB = IVold.VOLUME_TYPE_OBB;
+ public static final int TYPE_STUB = IVold.VOLUME_TYPE_STUB;
public static final int STATE_UNMOUNTED = IVold.VOLUME_STATE_UNMOUNTED;
public static final int STATE_CHECKING = IVold.VOLUME_STATE_CHECKING;
@@ -295,7 +296,7 @@
}
public boolean isVisibleForUser(int userId) {
- if (type == TYPE_PUBLIC && mountUserId == userId) {
+ if ((type == TYPE_PUBLIC || type == TYPE_STUB) && mountUserId == userId) {
return isVisible();
} else if (type == TYPE_EMULATED) {
return isVisible();
@@ -327,7 +328,7 @@
public File getPathForUser(int userId) {
if (path == null) {
return null;
- } else if (type == TYPE_PUBLIC) {
+ } else if (type == TYPE_PUBLIC || type == TYPE_STUB) {
return new File(path);
} else if (type == TYPE_EMULATED) {
return new File(path, Integer.toString(userId));
@@ -344,7 +345,7 @@
public File getInternalPathForUser(int userId) {
if (path == null) {
return null;
- } else if (type == TYPE_PUBLIC) {
+ } else if (type == TYPE_PUBLIC || type == TYPE_STUB) {
// TODO: plumb through cleaner path from vold
return new File(path.replace("/storage/", "/mnt/media_rw/"));
} else {
@@ -390,7 +391,7 @@
removable = true;
}
- } else if (type == TYPE_PUBLIC) {
+ } else if (type == TYPE_PUBLIC || type == TYPE_STUB) {
emulated = false;
removable = true;
@@ -447,7 +448,8 @@
public @Nullable Intent buildBrowseIntentForUser(int userId) {
final Uri uri;
- if (type == VolumeInfo.TYPE_PUBLIC && mountUserId == userId) {
+ if ((type == VolumeInfo.TYPE_PUBLIC || type == VolumeInfo.TYPE_STUB)
+ && mountUserId == userId) {
uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY, fsUuid);
} else if (type == VolumeInfo.TYPE_EMULATED && isPrimary()) {
uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY,
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 9341d9a..adff4d6 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -110,7 +110,6 @@
jclass mClass;
jmethodID mGetInstance;
jmethodID mSendDeathNotice;
- jmethodID mDumpProxyDebugInfo;
// Object state.
jfieldID mNativeData; // Field holds native pointer to BinderProxyNativeData.
@@ -1038,18 +1037,6 @@
static void android_os_BinderInternal_proxyLimitcallback(int uid)
{
JNIEnv *env = AndroidRuntime::getJNIEnv();
- {
- // Calls into BinderProxy must be serialized
- AutoMutex _l(gProxyLock);
- env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
- gBinderProxyOffsets.mDumpProxyDebugInfo);
- }
- if (env->ExceptionCheck()) {
- ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
- report_exception(env, excep.get(),
- "*** Uncaught exception in dumpProxyDebugInfo");
- }
-
env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
gBinderInternalOffsets.mProxyLimitCallback,
uid);
@@ -1439,8 +1426,6 @@
"(JJ)Landroid/os/BinderProxy;");
gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
"(Landroid/os/IBinder$DeathRecipient;)V");
- gBinderProxyOffsets.mDumpProxyDebugInfo = GetStaticMethodIDOrDie(env, clazz, "dumpProxyDebugInfo",
- "()V");
gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");
clazz = FindClassOrDie(env, "java/lang/Class");
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 0a720a5..4a9c356 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -184,7 +184,8 @@
title = mStorageManager.getBestVolumeDescription(privateVol);
storageUuid = StorageManager.convert(privateVol.fsUuid);
}
- } else if (volume.getType() == VolumeInfo.TYPE_PUBLIC
+ } else if ((volume.getType() == VolumeInfo.TYPE_PUBLIC
+ || volume.getType() == VolumeInfo.TYPE_STUB)
&& volume.getMountUserId() == userId) {
rootId = volume.getFsUuid();
title = mStorageManager.getBestVolumeDescription(volume);
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index 5a57e69..8f9394f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -152,7 +152,8 @@
final MeasurementDetails details = new MeasurementDetails();
if (mVolume == null) return details;
- if (mVolume.getType() == VolumeInfo.TYPE_PUBLIC) {
+ if (mVolume.getType() == VolumeInfo.TYPE_PUBLIC
+ || mVolume.getType() == VolumeInfo.TYPE_STUB) {
details.totalSize = mVolume.getPath().getTotalSpace();
details.availSize = mVolume.getPath().getUsableSpace();
return details;
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3b71cd9..d11a74f 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1190,6 +1190,9 @@
} else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
+ } else if (vol.type == VolumeInfo.TYPE_STUB) {
+ vol.mountUserId = mCurrentUserId;
+ mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
} else {
Slog.d(TAG, "Skipping automatic mounting of " + vol);
}
@@ -1200,6 +1203,7 @@
case VolumeInfo.TYPE_PRIVATE:
case VolumeInfo.TYPE_PUBLIC:
case VolumeInfo.TYPE_EMULATED:
+ case VolumeInfo.TYPE_STUB:
break;
default:
return false;
@@ -1276,7 +1280,8 @@
}
}
- if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
+ if ((vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_STUB)
+ && vol.state == VolumeInfo.STATE_EJECTING) {
// TODO: this should eventually be handled by new ObbVolume state changes
/*
* Some OBBs might have been unmounted when this volume was
@@ -1358,7 +1363,8 @@
}
boolean isTypeRestricted = false;
- if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
+ if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE
+ || vol.type == VolumeInfo.TYPE_STUB) {
isTypeRestricted = userManager
.hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
Binder.getCallingUserHandle());
@@ -2749,6 +2755,7 @@
final VolumeInfo vol = mVolumes.valueAt(i);
switch (vol.getType()) {
case VolumeInfo.TYPE_PUBLIC:
+ case VolumeInfo.TYPE_STUB:
case VolumeInfo.TYPE_EMULATED:
break;
default:
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7aadcd4..fa9c58e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -318,6 +318,7 @@
import android.net.Uri;
import android.os.BatteryStats;
import android.os.Binder;
+import android.os.BinderProxy;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
@@ -15210,6 +15211,7 @@
public void onLimitReached(int uid) {
Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
+ Process.myUid());
+ BinderProxy.dumpProxyDebugInfo();
if (uid == Process.SYSTEM_UID) {
Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
} else {
@@ -16061,8 +16063,10 @@
}
} else if ("binder-proxies".equals(cmd)) {
if (opti >= args.length) {
+ dumpBinderProxyInterfaceCounts(pw,
+ "Top proxy interface names held by SYSTEM");
dumpBinderProxiesCounts(pw, BinderInternal.nGetBinderProxyPerUidCounts(),
- "Counts of Binder Proxies held by SYSTEM");
+ "Number of proxies per uid held by SYSTEM");
} else {
String uid = args[opti];
opti++;
@@ -16565,6 +16569,15 @@
return printed;
}
+ void dumpBinderProxyInterfaceCounts(PrintWriter pw, String header) {
+ final BinderProxy.InterfaceCount[] proxyCounts = BinderProxy.getSortedInterfaceCounts(50);
+
+ pw.println(header);
+ for (int i = 0; i < proxyCounts.length; i++) {
+ pw.println(" #" + (i + 1) + ": " + proxyCounts[i]);
+ }
+ }
+
boolean dumpBinderProxiesCounts(PrintWriter pw, SparseIntArray counts, String header) {
if(counts != null) {
pw.println(header);