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

Commit 9ae4a083 authored by Daichi Hirono's avatar Daichi Hirono Committed by Android (Google) Code Review
Browse files

Merge "Stops performing operations that does not supported by MTP device." into nyc-dev

parents 07097610 0f32537e
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -133,6 +133,8 @@ public class AppFuse {
            return mCallback.readObjectBytes(inode, offset, size, mBuffer);
            return mCallback.readObjectBytes(inode, offset, size, mBuffer);
        } catch (IOException e) {
        } catch (IOException e) {
            return -OsConstants.EIO;
            return -OsConstants.EIO;
        } catch (UnsupportedOperationException e) {
            return -OsConstants.ENOTSUP;
        }
        }
    }
    }


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


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


        extraValues.put(
        extraValues.put(Root.COLUMN_FLAGS, getRootFlags(operationsSupported));
                Root.COLUMN_FLAGS,
                Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
        extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace);
        extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace);
        extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity);
        extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity);
        extraValues.put(Root.COLUMN_MIME_TYPES, "");
        extraValues.put(Root.COLUMN_MIME_TYPES, "");
@@ -785,6 +785,14 @@ class MtpDatabase {
        return "application/octet-stream";
        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) {
    static String[] strings(Object... args) {
        final String[] results = new String[args.length];
        final String[] results = new String[args.length];
        for (int i = 0; i < args.length; i++) {
        for (int i = 0; i < args.length; i++) {
+26 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.mtp;
package com.android.mtp;


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


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


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

    String getDeviceName(int deviceId) throws IOException {
        synchronized (mDeviceListLock) {
        synchronized (mDeviceListLock) {
            for (final MtpDeviceRecord device : mMtpManager.getDevices()) {
            final MtpDeviceRecord[] records = new MtpDeviceRecord[mDeviceToolkits.size()];
                if (device.deviceId == deviceId) {
            int i = 0;
                    return device.name;
            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() {
    public void shutdown() {
        synchronized (mDeviceListLock) {
        synchronized (mDeviceListLock) {
            try {
            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);
                    closeDeviceInternal(id);
                }
                }
            } catch (InterruptedException|IOException e) {
            } catch (InterruptedException|IOException e) {
@@ -432,7 +441,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        getDeviceToolkit(deviceId).mDocumentLoader.close();
        getDeviceToolkit(deviceId).mDocumentLoader.close();
        mDeviceToolkits.remove(deviceId);
        mDeviceToolkits.remove(deviceId);
        mMtpManager.closeDevice(deviceId);
        mMtpManager.closeDevice(deviceId);
        if (getOpenedDeviceIds().length == 0) {
        if (mDeviceToolkits.size() == 0) {
            mRootScanner.pause();
            mRootScanner.pause();
        }
        }
    }
    }
@@ -488,11 +497,14 @@ public class MtpDocumentsProvider extends DocumentsProvider {
    private static class DeviceToolkit {
    private static class DeviceToolkit {
        public final PipeManager mPipeManager;
        public final PipeManager mPipeManager;
        public final DocumentLoader mDocumentLoader;
        public final DocumentLoader mDocumentLoader;
        public final MtpDeviceRecord mDeviceRecord;


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


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


        @Override
        @Override
Loading