summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--core/java/android/os/BinderProxy.java128
-rw-r--r--core/java/android/os/FileUtils.java37
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java3
-rw-r--r--core/jni/android_util_Binder.cpp15
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java25
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java15
-rw-r--r--services/core/java/com/android/server/storage/AppFuseBridge.java22
-rw-r--r--telephony/java/android/provider/Telephony.java53
-rw-r--r--telephony/java/android/telephony/RcsManager.java52
-rw-r--r--telephony/java/com/android/internal/telephony/IRcs.aidl21
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyIntents.java14
13 files changed, 307 insertions, 81 deletions
diff --git a/Android.bp b/Android.bp
index 170e22e1cbde..f49e4e5eb496 100644
--- a/Android.bp
+++ b/Android.bp
@@ -546,6 +546,7 @@ java_defaults {
"telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl",
"telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl",
"telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl",
+ "telephony/java/com/android/internal/telephony/IRcs.aidl",
"telephony/java/com/android/internal/telephony/ISms.aidl",
"telephony/java/com/android/internal/telephony/ISub.aidl",
"telephony/java/com/android/internal/telephony/IAns.aidl",
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index e492f88d4329..591370ff728b 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -225,10 +225,11 @@ public final class BinderProxy implements IBinder {
}
}
- /**
- * 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 @@ public final class BinderProxy implements IBinder {
}
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 @@ public final class BinderProxy implements IBinder {
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 @@ public final class BinderProxy implements IBinder {
*/
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 @@ public final class BinderProxy implements IBinder {
}
}
- 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/FileUtils.java b/core/java/android/os/FileUtils.java
index 88d6e847b644..ddeb8380c331 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -16,6 +16,18 @@
package android.os;
+import static android.os.ParcelFileDescriptor.MODE_APPEND;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
+import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_RDONLY;
+import static android.system.OsConstants.O_RDWR;
+import static android.system.OsConstants.O_TRUNC;
+import static android.system.OsConstants.O_WRONLY;
import static android.system.OsConstants.SPLICE_F_MORE;
import static android.system.OsConstants.SPLICE_F_MOVE;
import static android.system.OsConstants.S_ISFIFO;
@@ -1050,6 +1062,30 @@ public class FileUtils {
return val * pow;
}
+ /** {@hide} */
+ public static int translateModePfdToPosix(int mode) {
+ int res = 0;
+ if ((mode & MODE_READ_WRITE) == MODE_READ_WRITE) {
+ res |= O_RDWR;
+ } else if ((mode & MODE_WRITE_ONLY) == MODE_WRITE_ONLY) {
+ res |= O_WRONLY;
+ } else if ((mode & MODE_READ_ONLY) == MODE_READ_ONLY) {
+ res |= O_RDONLY;
+ } else {
+ throw new IllegalArgumentException("Bad mode: " + mode);
+ }
+ if ((mode & MODE_CREATE) == MODE_CREATE) {
+ res |= O_CREAT;
+ }
+ if ((mode & MODE_TRUNCATE) == MODE_TRUNCATE) {
+ res |= O_TRUNC;
+ }
+ if ((mode & MODE_APPEND) == MODE_APPEND) {
+ res |= O_APPEND;
+ }
+ return res;
+ }
+
@VisibleForTesting
public static class MemoryPipe extends Thread implements AutoCloseable {
private final FileDescriptor[] pipe;
@@ -1115,3 +1151,4 @@ public class FileUtils {
}
}
}
+
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 7409ca741c52..81fc5c0303d5 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -1092,6 +1092,9 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
/**
* Internal class representing a remote status read by
* {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
+ *
+ * Warning: this must be kept in sync with ParcelFileDescriptorStatus at
+ * frameworks/native/libs/binder/Parcel.cpp
*/
private static class Status {
/** Special value indicating remote side died. */
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 9341d9a48913..adff4d644c08 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -110,7 +110,6 @@ static struct binderproxy_offsets_t
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_handleGc(JNIEnv* env, jobject clazz)
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 @@ static int int_register_android_os_BinderProxy(JNIEnv* env)
"(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/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1f3a8fce8ef1..9ce6044bcf3e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -398,6 +398,8 @@
<protected-broadcast android:name="android.telecom.action.DEFAULT_DIALER_CHANGED" />
<protected-broadcast android:name="android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED" />
+ <protected-broadcast android:name="android.provider.action.SMS_MMS_DB_CREATED" />
+ <protected-broadcast android:name="android.provider.action.SMS_MMS_DB_LOST" />
<protected-broadcast android:name="android.intent.action.CONTENT_CHANGED" />
<protected-broadcast android:name="android.provider.Telephony.MMS_DOWNLOADED" />
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index d11a74fd404c..a3e6ea2518a6 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2602,24 +2602,35 @@ class StorageManagerService extends IStorageManager.Stub
class AppFuseMountScope extends AppFuseBridge.MountScope {
boolean opened = false;
- public AppFuseMountScope(int uid, int pid, int mountId) {
- super(uid, pid, mountId);
+ public AppFuseMountScope(int uid, int mountId) {
+ super(uid, mountId);
}
@Override
public ParcelFileDescriptor open() throws NativeDaemonConnectorException {
try {
return new ParcelFileDescriptor(
- mVold.mountAppFuse(uid, Process.myPid(), mountId));
+ mVold.mountAppFuse(uid, mountId));
} catch (Exception e) {
throw new NativeDaemonConnectorException("Failed to mount", e);
}
}
@Override
+ public ParcelFileDescriptor openFile(int mountId, int fileId, int flags)
+ throws NativeDaemonConnectorException {
+ try {
+ return new ParcelFileDescriptor(
+ mVold.openAppFuseFile(uid, mountId, fileId, flags));
+ } catch (Exception e) {
+ throw new NativeDaemonConnectorException("Failed to open", e);
+ }
+ }
+
+ @Override
public void close() throws Exception {
if (opened) {
- mVold.unmountAppFuse(uid, Process.myPid(), mountId);
+ mVold.unmountAppFuse(uid, mountId);
opened = false;
}
}
@@ -2629,7 +2640,6 @@ class StorageManagerService extends IStorageManager.Stub
public @Nullable AppFuseMount mountProxyFileDescriptorBridge() {
Slog.v(TAG, "mountProxyFileDescriptorBridge");
final int uid = Binder.getCallingUid();
- final int pid = Binder.getCallingPid();
while (true) {
synchronized (mAppFuseLock) {
@@ -2643,7 +2653,7 @@ class StorageManagerService extends IStorageManager.Stub
final int name = mNextAppFuseName++;
try {
return new AppFuseMount(
- name, mAppFuseBridge.addBridge(new AppFuseMountScope(uid, pid, name)));
+ name, mAppFuseBridge.addBridge(new AppFuseMountScope(uid, name)));
} catch (FuseUnavailableMountException e) {
if (newlyCreated) {
// If newly created bridge fails, it's a real error.
@@ -2664,14 +2674,13 @@ class StorageManagerService extends IStorageManager.Stub
public @Nullable ParcelFileDescriptor openProxyFileDescriptor(
int mountId, int fileId, int mode) {
Slog.v(TAG, "mountProxyFileDescriptor");
- final int pid = Binder.getCallingPid();
try {
synchronized (mAppFuseLock) {
if (mAppFuseBridge == null) {
Slog.e(TAG, "FuseBridge has not been created");
return null;
}
- return mAppFuseBridge.openFile(pid, mountId, fileId, mode);
+ return mAppFuseBridge.openFile(mountId, fileId, mode);
}
} catch (FuseUnavailableMountException | InterruptedException error) {
Slog.v(TAG, "The mount point has already been invalid", error);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7aadcd400f0e..fa9c58e1955c 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.ProxyInfo;
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 class ActivityManagerService extends IActivityManager.Stub
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 @@ public class ActivityManagerService extends IActivityManager.Stub
}
} 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 @@ public class ActivityManagerService extends IActivityManager.Stub
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);
diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java
index 6a0b6489f470..9d6a64701e85 100644
--- a/services/core/java/com/android/server/storage/AppFuseBridge.java
+++ b/services/core/java/com/android/server/storage/AppFuseBridge.java
@@ -16,6 +16,7 @@
package com.android.server.storage;
+import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.Os;
@@ -25,8 +26,6 @@ import com.android.internal.os.FuseUnavailableMountException;
import com.android.internal.util.Preconditions;
import com.android.server.NativeDaemonConnectorException;
import libcore.io.IoUtils;
-import java.io.File;
-import java.io.FileNotFoundException;
import java.util.concurrent.CountDownLatch;
/**
@@ -87,7 +86,7 @@ public class AppFuseBridge implements Runnable {
}
}
- public ParcelFileDescriptor openFile(int pid, int mountId, int fileId, int mode)
+ public ParcelFileDescriptor openFile(int mountId, int fileId, int mode)
throws FuseUnavailableMountException, InterruptedException {
final MountScope scope;
synchronized (this) {
@@ -96,17 +95,14 @@ public class AppFuseBridge implements Runnable {
throw new FuseUnavailableMountException(mountId);
}
}
- if (scope.pid != pid) {
- throw new SecurityException("PID does not match");
- }
final boolean result = scope.waitForMount();
if (result == false) {
throw new FuseUnavailableMountException(mountId);
}
try {
- return ParcelFileDescriptor.open(
- new File(scope.mountPoint, String.valueOf(fileId)), mode);
- } catch (FileNotFoundException error) {
+ int flags = FileUtils.translateModePfdToPosix(mode);
+ return scope.openFile(mountId, fileId, flags);
+ } catch (NativeDaemonConnectorException error) {
throw new FuseUnavailableMountException(mountId);
}
}
@@ -131,17 +127,13 @@ public class AppFuseBridge implements Runnable {
public static abstract class MountScope implements AutoCloseable {
public final int uid;
- public final int pid;
public final int mountId;
- public final File mountPoint;
private final CountDownLatch mMounted = new CountDownLatch(1);
private boolean mMountResult = false;
- public MountScope(int uid, int pid, int mountId) {
+ public MountScope(int uid, int mountId) {
this.uid = uid;
- this.pid = pid;
this.mountId = mountId;
- this.mountPoint = new File(String.format(APPFUSE_MOUNT_NAME_TEMPLATE, uid, mountId));
}
@GuardedBy("AppFuseBridge.this")
@@ -159,6 +151,8 @@ public class AppFuseBridge implements Runnable {
}
public abstract ParcelFileDescriptor open() throws NativeDaemonConnectorException;
+ public abstract ParcelFileDescriptor openFile(int mountId, int fileId, int flags)
+ throws NativeDaemonConnectorException;
}
private native long native_new();
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 7b798e8f185a..efea81763b9f 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -16,6 +16,7 @@
package android.provider;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -1181,6 +1182,58 @@ public final class Telephony {
"android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL";
/**
+ * Broadcast action: When SMS-MMS db is being created. If file-based encryption is
+ * supported, this broadcast indicates creation of the db in credential-encrypted
+ * storage. A boolean is specified in {@link #EXTRA_IS_INITIAL_CREATE} to indicate if
+ * this is the initial create of the db. Requires
+ * {@link android.Manifest.permission#READ_SMS} to receive.
+ *
+ * @see #EXTRA_IS_INITIAL_CREATE
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SMS_MMS_DB_CREATED =
+ "android.provider.action.SMS_MMS_DB_CREATED";
+
+ /**
+ * Boolean flag passed as an extra with {@link #ACTION_SMS_MMS_DB_CREATED} to indicate
+ * whether the DB creation is the initial creation on the device, that is it is after a
+ * factory-data reset or a new device. Any subsequent creations of the DB (which
+ * happens only in error scenarios) will have this flag set to false.
+ *
+ * @see #ACTION_SMS_MMS_DB_CREATED
+ *
+ * @hide
+ */
+ public static final String EXTRA_IS_INITIAL_CREATE =
+ "android.provider.extra.IS_INITIAL_CREATE";
+
+ /**
+ * Broadcast intent action indicating that the telephony provider SMS MMS database is
+ * corrupted. A boolean is specified in {@link #EXTRA_IS_CORRUPTED} to indicate if the
+ * database is corrupted. Requires the
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE permission.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final String ACTION_SMS_MMS_DB_LOST =
+ "android.provider.action.SMS_MMS_DB_LOST";
+
+ /**
+ * Boolean flag passed as an extra with {@link #ACTION_SMS_MMS_DB_LOST} to indicate
+ * whether the DB got corrupted or not.
+ *
+ * @see #ACTION_SMS_MMS_DB_LOST
+ *
+ * @hide
+ */
+ public static final String EXTRA_IS_CORRUPTED =
+ "android.provider.extra.IS_CORRUPTED";
+
+ /**
* Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a
* {@link #DATA_SMS_RECEIVED_ACTION} intent.
*
diff --git a/telephony/java/android/telephony/RcsManager.java b/telephony/java/android/telephony/RcsManager.java
new file mode 100644
index 000000000000..00ce03a1f668
--- /dev/null
+++ b/telephony/java/android/telephony/RcsManager.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.telephony.IRcs;
+
+/**
+ * RcsManager is the application interface to RcsProvider and provides access methods to
+ * RCS related database tables.
+ * @hide - TODO make this public
+ */
+public class RcsManager {
+ private static final String TAG = "RcsManager";
+ private static final boolean VDBG = false;
+
+ /**
+ * Delete the RcsThread identified by the given threadId.
+ * @param threadId threadId of the thread to be deleted.
+ */
+ public void deleteThread(int threadId) {
+ if (VDBG) logd("deleteThread: threadId: " + threadId);
+ try {
+ IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+ if (iRcs != null) {
+ iRcs.deleteThread(threadId);
+ }
+ } catch (RemoteException re) {
+
+ }
+ }
+
+ private static void logd(String msg) {
+ Rlog.d(TAG, msg);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IRcs.aidl b/telephony/java/com/android/internal/telephony/IRcs.aidl
new file mode 100644
index 000000000000..ede8695ef08e
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IRcs.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 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.internal.telephony;
+
+interface IRcs {
+ void deleteThread(int threadId);
+} \ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 5ecb43ebf112..2a648bd8b252 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -480,9 +480,9 @@ public class TelephonyIntents {
public static final String EXTRA_PCO_VALUE_KEY = "pcoValue";
public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE_KEY = "defaultNetworkAvailable";
- /**
+ /**
* Broadcast action to trigger CI OMA-DM Session.
- */
+ */
public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE =
"com.android.omadm.service.CONFIGURATION_UPDATE";
@@ -491,4 +491,14 @@ public class TelephonyIntents {
*/
public static final String ACTION_CARRIER_CERTIFICATE_DOWNLOAD =
"com.android.internal.telephony.ACTION_CARRIER_CERTIFICATE_DOWNLOAD";
+
+ /**
+ * Broadcast action to indicate an error related to Line1Number has been detected.
+ *
+ * Requires the READ_PRIVILEGED_PHONE_STATE permission.
+ *
+ * @hide
+ */
+ public static final String ACTION_LINE1_NUMBER_ERROR_DETECTED =
+ "com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED";
}