Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0f32537e authored by Daichi Hirono's avatar Daichi Hirono
Browse files

Stops performing operations that does not supported by MTP device.

MTP devices can return supported operation list. The CL sets root flag
by referring it.

BUG=26147375

Change-Id: I02397821e208cf5a8fcf7457aa279d2818ce24c7
parent 52cdc159
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -133,6 +133,8 @@ public class AppFuse {
            return mCallback.readObjectBytes(inode, offset, size, mBuffer);
        } catch (IOException e) {
            return -OsConstants.EIO;
        } catch (UnsupportedOperationException e) {
            return -OsConstants.ENOTSUP;
        }
    }

+7 −2
Original line number Diff line number Diff line
@@ -89,7 +89,8 @@ class Mapper {
     * @return If roots are added or removed from the database.
     * @throws FileNotFoundException
     */
    synchronized boolean putStorageDocuments(String parentDocumentId, MtpRoot[] roots)
    synchronized boolean putStorageDocuments(
            String parentDocumentId, int[] operationsSupported, MtpRoot[] roots)
            throws FileNotFoundException {
        final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
        database.beginTransaction();
@@ -100,7 +101,11 @@ class Mapper {
                valuesList[i] = new ContentValues();
                extraValuesList[i] = new ContentValues();
                MtpDatabase.getStorageDocumentValues(
                        valuesList[i], extraValuesList[i], parentDocumentId, roots[i]);
                        valuesList[i],
                        extraValuesList[i],
                        parentDocumentId,
                        operationsSupported,
                        roots[i]);
            }
            final boolean changed = putDocuments(
                    parentDocumentId,
+14 −6
Original line number Diff line number Diff line
@@ -689,9 +689,7 @@ class MtpDatabase {
        values.putNull(Document.COLUMN_SIZE);

        extraValues.clear();
        extraValues.put(
                Root.COLUMN_FLAGS,
                Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
        extraValues.put(Root.COLUMN_FLAGS, getRootFlags(device.operationsSupported));
        extraValues.putNull(Root.COLUMN_AVAILABLE_BYTES);
        extraValues.putNull(Root.COLUMN_CAPACITY_BYTES);
        extraValues.put(Root.COLUMN_MIME_TYPES, "");
@@ -700,12 +698,16 @@ class MtpDatabase {
    /**
     * Gets {@link ContentValues} for the given root.
     * @param values {@link ContentValues} that receives values.
     * @param extraValues {@link ContentValues} that receives extra values for roots.
     * @param parentDocumentId Parent document ID.
     * @param supportedOperations Array of Operation code supported by the device.
     * @param root Root to be converted {@link ContentValues}.
     */
    static void getStorageDocumentValues(
            ContentValues values,
            ContentValues extraValues,
            String parentDocumentId,
            int[] operationsSupported,
            MtpRoot root) {
        values.clear();
        values.put(COLUMN_DEVICE_ID, root.mDeviceId);
@@ -722,9 +724,7 @@ class MtpDatabase {
        values.put(Document.COLUMN_FLAGS, 0);
        values.put(Document.COLUMN_SIZE, root.mMaxCapacity - root.mFreeSpace);

        extraValues.put(
                Root.COLUMN_FLAGS,
                Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
        extraValues.put(Root.COLUMN_FLAGS, getRootFlags(operationsSupported));
        extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace);
        extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity);
        extraValues.put(Root.COLUMN_MIME_TYPES, "");
@@ -785,6 +785,14 @@ class MtpDatabase {
        return "application/octet-stream";
    }

    private static int getRootFlags(int[] operationsSupported) {
        int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD;
        if (MtpDeviceRecord.isWritingSupported(operationsSupported)) {
            rootFlag |= Root.FLAG_SUPPORTS_CREATE;
        }
        return rootFlag;
    }

    static String[] strings(Object... args) {
        final String[] results = new String[args.length];
        for (int i = 0; i < args.length; i++) {
+26 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.mtp;

import android.annotation.Nullable;
import android.mtp.MtpConstants;

class MtpDeviceRecord {
    public final int deviceId;
@@ -38,4 +39,29 @@ class MtpDeviceRecord {
        this.operationsSupported = operationsSupported;
        this.eventsSupported = eventsSupported;
    }

    /**
     * Helper method to check operations/events are supported by the device or not.
     */
    static boolean isSupported(@Nullable int[] supportedList, int code) {
        if (supportedList == null) {
            return false;
        }
        for (int i = 0; i < supportedList.length; i++) {
            if (supportedList[i] == code) {
                return true;
            }
        }
        return false;
    }

    static boolean isPartialReadSupported(@Nullable int[] supportedList, long fileSize) {
        return fileSize <= 0xffffffffl &&
                 isSupported(supportedList, MtpConstants.OPERATION_GET_PARTIAL_OBJECT);
    }

    static boolean isWritingSupported(@Nullable int[] supportedList) {
        return isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT_INFO) &&
                isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT);
    }
}
+39 −22
Original line number Diff line number Diff line
@@ -201,6 +201,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        final Identifier identifier = mDatabase.createIdentifier(documentId);
        try {
            openDevice(identifier.mDeviceId);
            final MtpDeviceRecord device = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
            switch (mode) {
                case "r":
                    final long fileSize = getFileSize(documentId);
@@ -208,7 +209,8 @@ public class MtpDocumentsProvider extends DocumentsProvider {
                    // 4GB. Fallback to non-seekable file descriptor.
                    // TODO: Use getPartialObject64 for MTP devices that support Android vendor
                    // extension.
                    if (fileSize <= 0xffffffffl) {
                    if (MtpDeviceRecord.isPartialReadSupported(
                            device.operationsSupported, fileSize)) {
                        return mAppFuse.openFile(Integer.parseInt(documentId));
                    } else {
                        return getPipeManager(identifier).readDocument(mMtpManager, identifier);
@@ -216,8 +218,13 @@ public class MtpDocumentsProvider extends DocumentsProvider {
                case "w":
                    // TODO: Clear the parent document loader task (if exists) and call notify
                    // when writing is completed.
                    if (MtpDeviceRecord.isWritingSupported(device.operationsSupported)) {
                        return getPipeManager(identifier).writeDocument(
                                getContext(), mMtpManager, identifier);
                    } else {
                        throw new UnsupportedOperationException(
                                "The device does not support writing operation.");
                    }
                case "rw":
                    // TODO: Add support for "rw" mode.
                    throw new UnsupportedOperationException(
@@ -290,6 +297,10 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        try {
            final Identifier parentId = mDatabase.createIdentifier(parentDocumentId);
            openDevice(parentId.mDeviceId);
            final MtpDeviceRecord record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord;
            if (!MtpDeviceRecord.isWritingSupported(record.operationsSupported)) {
                throw new UnsupportedOperationException();
            }
            final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe();
            pipe[0].close();  // 0 bytes for a new document.
            final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ?
@@ -323,9 +334,9 @@ public class MtpDocumentsProvider extends DocumentsProvider {
            if (DEBUG) {
                Log.d(TAG, "Open device " + deviceId);
            }
            mMtpManager.openDevice(deviceId);
            final MtpDeviceRecord device = mMtpManager.openDevice(deviceId);
            final DeviceToolkit toolkit =
                    new DeviceToolkit(deviceId, mMtpManager, mResolver, mDatabase);
                    new DeviceToolkit(deviceId, mMtpManager, mResolver, mDatabase, device);
            mDeviceToolkits.put(deviceId, toolkit);
            mIntentSender.sendUpdateNotificationIntent();
            try {
@@ -347,20 +358,15 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        mIntentSender.sendUpdateNotificationIntent();
    }

    int[] getOpenedDeviceIds() {
        synchronized (mDeviceListLock) {
            return mMtpManager.getOpenedDeviceIds();
        }
    }

    String getDeviceName(int deviceId) throws IOException {
    MtpDeviceRecord[] getOpenedDeviceRecordsCache() {
        synchronized (mDeviceListLock) {
            for (final MtpDeviceRecord device : mMtpManager.getDevices()) {
                if (device.deviceId == deviceId) {
                    return device.name;
                }
            final MtpDeviceRecord[] records = new MtpDeviceRecord[mDeviceToolkits.size()];
            int i = 0;
            for (final DeviceToolkit toolkit : mDeviceToolkits.values()) {
                records[i] = toolkit.mDeviceRecord;
                i++;
            }
            throw new IOException("Not found the device: " + Integer.toString(deviceId));
            return records;
        }
    }

@@ -391,7 +397,10 @@ public class MtpDocumentsProvider extends DocumentsProvider {
    public void shutdown() {
        synchronized (mDeviceListLock) {
            try {
                for (final int id : mMtpManager.getOpenedDeviceIds()) {
                // Copy the opened key set because it will be modified when closing devices.
                final Integer[] keySet =
                        mDeviceToolkits.keySet().toArray(new Integer[mDeviceToolkits.size()]);
                for (final int id : keySet) {
                    closeDeviceInternal(id);
                }
            } catch (InterruptedException|IOException e) {
@@ -432,7 +441,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        getDeviceToolkit(deviceId).mDocumentLoader.close();
        mDeviceToolkits.remove(deviceId);
        mMtpManager.closeDevice(deviceId);
        if (getOpenedDeviceIds().length == 0) {
        if (mDeviceToolkits.size() == 0) {
            mRootScanner.pause();
        }
    }
@@ -488,11 +497,14 @@ public class MtpDocumentsProvider extends DocumentsProvider {
    private static class DeviceToolkit {
        public final PipeManager mPipeManager;
        public final DocumentLoader mDocumentLoader;
        public final MtpDeviceRecord mDeviceRecord;

        public DeviceToolkit(
                int deviceId, MtpManager manager, ContentResolver resolver, MtpDatabase database) {
                int deviceId, MtpManager manager, ContentResolver resolver, MtpDatabase database,
                MtpDeviceRecord record) {
            mPipeManager = new PipeManager(database);
            mDocumentLoader = new DocumentLoader(deviceId, manager, resolver, database);
            mDeviceRecord = record;
        }
    }

@@ -501,8 +513,13 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        public long readObjectBytes(
                int inode, long offset, long size, byte[] buffer) throws IOException {
            final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode));
            final MtpDeviceRecord record = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
            if (MtpDeviceRecord.isPartialReadSupported(record.operationsSupported, offset)) {
                return mMtpManager.getPartialObject(
                        identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
            } else {
                throw new UnsupportedOperationException();
            }
        }

        @Override
Loading