Merge changes I9971c466,Ib42474fd into mnc-dev

* changes:
  Kill MediaProvider during drastic changes.
  Use best volume description for MTP.
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index a4ee8b7..32f7bc9 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
-import android.mtp.MtpStorage;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.Parcel;
@@ -300,6 +299,8 @@
     }
 
     public StorageVolume buildStorageVolume(Context context, int userId) {
+        final StorageManager storage = context.getSystemService(StorageManager.class);
+
         final boolean removable;
         final boolean emulated;
         final boolean allowMassStorage = false;
@@ -310,14 +311,7 @@
             userPath = new File("/dev/null");
         }
 
-        String description = getDescription();
-        if (description == null) {
-            description = getFsUuid();
-        }
-        if (description == null) {
-            description = context.getString(android.R.string.unknownName);
-        }
-
+        String description = null;
         long mtpReserveSize = 0;
         long maxFileSize = 0;
         int mtpStorageId = StorageVolume.STORAGE_ID_INVALID;
@@ -325,11 +319,16 @@
         if (type == TYPE_EMULATED) {
             emulated = true;
 
+            final VolumeInfo privateVol = storage.findPrivateForEmulated(this);
+            if (privateVol != null) {
+                description = storage.getBestVolumeDescription(privateVol);
+            }
+
             if (isPrimary()) {
                 mtpStorageId = StorageVolume.STORAGE_ID_PRIMARY;
             }
 
-            mtpReserveSize = StorageManager.from(context).getStorageLowBytes(userPath);
+            mtpReserveSize = storage.getStorageLowBytes(userPath);
 
             if (ID_EMULATED_INTERNAL.equals(id)) {
                 removable = false;
@@ -341,6 +340,8 @@
             emulated = false;
             removable = true;
 
+            description = storage.getBestVolumeDescription(this);
+
             if (isPrimary()) {
                 mtpStorageId = StorageVolume.STORAGE_ID_PRIMARY;
             } else {
@@ -357,6 +358,10 @@
             throw new IllegalStateException("Unexpected volume type " + type);
         }
 
+        if (description == null) {
+            description = context.getString(android.R.string.unknownName);
+        }
+
         return new StorageVolume(id, mtpStorageId, userPath, description, isPrimary(), removable,
                 emulated, mtpReserveSize, allowMassStorage, maxFileSize, new UserHandle(userId),
                 fsUuid, envState);
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index c7ca1ab..25bd787 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -31,6 +31,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
+import android.app.IActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -39,10 +40,10 @@
 import android.content.ServiceConnection;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.ObbInfo;
-import android.mtp.MtpStorage;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.DropBoxManager;
@@ -53,7 +54,6 @@
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteCallbackList;
@@ -73,6 +73,7 @@
 import android.os.storage.StorageVolume;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
+import android.provider.MediaStore;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
@@ -176,7 +177,6 @@
         }
     }
 
-    private static final boolean LOCAL_LOGD = false;
     private static final boolean DEBUG_EVENTS = false;
     private static final boolean DEBUG_OBB = false;
 
@@ -723,10 +723,30 @@
         MountServiceIdler.scheduleIdlePass(mContext);
     }
 
+    /**
+     * MediaProvider has a ton of code that makes assumptions about storage
+     * paths never changing, so we outright kill them to pick up new state.
+     */
+    @Deprecated
+    private void killMediaProvider() {
+        final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY, 0,
+                UserHandle.USER_OWNER);
+        if (provider != null) {
+            final IActivityManager am = ActivityManagerNative.getDefault();
+            try {
+                am.killApplicationWithAppId(provider.applicationInfo.packageName,
+                        UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
     private void resetIfReadyAndConnectedLocked() {
         Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
                 + ", mDaemonConnected=" + mDaemonConnected);
         if (mSystemReady && mDaemonConnected) {
+            killMediaProvider();
+
             mDisks.clear();
             mVolumes.clear();
 
@@ -1606,7 +1626,9 @@
         waitForReady();
 
         try {
-            final NativeDaemonEvent res = mConnector.execute("volume", "benchmark", volId);
+            // TODO: make benchmark async so we don't block other commands
+            final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
+                    "volume", "benchmark", volId);
             return Long.parseLong(res.getMessage());
         } catch (NativeDaemonTimeoutException e) {
             return Long.MAX_VALUE;
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index e7979e4..519a2a3 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -69,7 +69,7 @@
 
     private AtomicInteger mSequenceNumber;
 
-    private static final int DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */
+    private static final long DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */
     private static final long WARN_EXECUTE_DELAY_MS = 500; /* .5 sec */
 
     /** Lock held whenever communicating with native daemon. */
@@ -337,7 +337,12 @@
      */
     public NativeDaemonEvent execute(String cmd, Object... args)
             throws NativeDaemonConnectorException {
-        final NativeDaemonEvent[] events = executeForList(cmd, args);
+        return execute(DEFAULT_TIMEOUT, cmd, args);
+    }
+
+    public NativeDaemonEvent execute(long timeoutMs, String cmd, Object... args)
+            throws NativeDaemonConnectorException {
+        final NativeDaemonEvent[] events = executeForList(timeoutMs, cmd, args);
         if (events.length != 1) {
             throw new NativeDaemonConnectorException(
                     "Expected exactly one response, but received " + events.length);
@@ -372,7 +377,7 @@
      */
     public NativeDaemonEvent[] executeForList(String cmd, Object... args)
             throws NativeDaemonConnectorException {
-            return execute(DEFAULT_TIMEOUT, cmd, args);
+        return executeForList(DEFAULT_TIMEOUT, cmd, args);
     }
 
     /**
@@ -387,7 +392,7 @@
      *             {@link NativeDaemonEvent#isClassClientError()} or
      *             {@link NativeDaemonEvent#isClassServerError()}.
      */
-    public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args)
+    public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
             throws NativeDaemonConnectorException {
         final long startTime = SystemClock.elapsedRealtime();
 
@@ -418,7 +423,7 @@
 
         NativeDaemonEvent event = null;
         do {
-            event = mResponseQueue.remove(sequenceNumber, timeout, logCmd);
+            event = mResponseQueue.remove(sequenceNumber, timeoutMs, logCmd);
             if (event == null) {
                 loge("timed-out waiting for response to " + logCmd);
                 throw new NativeDaemonTimeoutException(logCmd, event);
@@ -606,7 +611,7 @@
 
         // note that the timeout does not count time in deep sleep.  If you don't want
         // the device to sleep, hold a wakelock
-        public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String logCmd) {
+        public NativeDaemonEvent remove(int cmdNum, long timeoutMs, String logCmd) {
             PendingCmd found = null;
             synchronized (mPendingCmds) {
                 for (PendingCmd pendingCmd : mPendingCmds) {