Recover from FUSE session starting failures

Vold calls into StorageManagerService which in turn calls into the
FUSE daemon to start the session. If the system_server is very busy
e.g right after an OTA, the session may not start quickly enough and
we will timeout, causing vold to fail the mount.

Previously, the only solution would be for the user to reboot.

Now, we naively retry every 10s.

Bug: 147610762
Test: Causing an artificial timeout when starting a session for the
firs time, verified we recover after a minute

Change-Id: Ifdb2384696e85b6774a12394798fca8eb75a584e
This commit is contained in:
Zim
2020-01-15 15:23:54 +00:00
committed by Zimuzo Ezeozue
parent c4b718ff79
commit 7924a51690
3 changed files with 22 additions and 10 deletions

View File

@@ -44,6 +44,7 @@ import static com.android.internal.util.XmlUtils.readStringAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
import static com.android.server.storage.StorageUserConnection.REMOTE_TIMEOUT_SECONDS;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -1985,16 +1986,28 @@ class StorageManagerService extends IStorageManager.Stub
Slog.i(TAG, "Mounting volume " + vol);
mVold.mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub() {
@Override
public boolean onVolumeChecking(FileDescriptor deviceFd, String path,
public boolean onVolumeChecking(FileDescriptor fd, String path,
String internalPath) {
vol.path = path;
vol.internalPath = internalPath;
ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
try {
mStorageSessionController.onVolumeMount(deviceFd, vol);
mStorageSessionController.onVolumeMount(pfd, vol);
return true;
} catch (ExternalStorageServiceException e) {
Slog.i(TAG, "Failed to mount volume " + vol, e);
Slog.e(TAG, "Failed to mount volume " + vol, e);
Slog.i(TAG, "Scheduling reset in one minute");
mHandler.removeMessages(H_RESET);
mHandler.sendMessageDelayed(mHandler.obtainMessage(H_RESET),
TimeUnit.SECONDS.toMillis(REMOTE_TIMEOUT_SECONDS * 2));
return false;
} finally {
try {
pfd.close();
} catch (Exception e) {
Slog.e(TAG, "Failed to close FUSE device fd", e);
}
}
}
});

View File

@@ -40,9 +40,7 @@ import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.util.Objects;
/**
@@ -82,7 +80,7 @@ public final class StorageSessionController {
* @throws ExternalStorageServiceException if the session fails to start
* @throws IllegalStateException if a session has already been created for {@code vol}
*/
public void onVolumeMount(FileDescriptor deviceFd, VolumeInfo vol)
public void onVolumeMount(ParcelFileDescriptor deviceFd, VolumeInfo vol)
throws ExternalStorageServiceException {
if (!shouldHandle(vol)) {
return;
@@ -102,8 +100,8 @@ public final class StorageSessionController {
mConnections.put(userId, connection);
}
Slog.i(TAG, "Creating and starting session with id: " + sessionId);
connection.startSession(sessionId, new ParcelFileDescriptor(deviceFd),
vol.getPath().getPath(), vol.getInternalPath().getPath());
connection.startSession(sessionId, deviceFd, vol.getPath().getPath(),
vol.getInternalPath().getPath());
}
}
@@ -185,7 +183,7 @@ public final class StorageSessionController {
* This call removes all sessions for the user that is being stopped;
* this will make sure that we don't rebind to the service needlessly.
*/
public void onUserStopping(int userId) throws ExternalStorageServiceException {
public void onUserStopping(int userId) {
if (!shouldHandle(null)) {
return;
}

View File

@@ -60,7 +60,8 @@ import java.util.concurrent.TimeoutException;
*/
public final class StorageUserConnection {
private static final String TAG = "StorageUserConnection";
private static final int REMOTE_TIMEOUT_SECONDS = 15;
public static final int REMOTE_TIMEOUT_SECONDS = 5;
private final Object mLock = new Object();
private final Context mContext;