[MediaProvider]MTP拷贝APK文件Observe

2018-09-26  本文已影响0人  Weller0

1、调用流程

发送ObjectInfo
MtpResponseCode MtpServer::doSendObjectInfo() //MtpServer.cpp
private int beginSendObject(String path, int format,...) //MtpDatabase.java
拷贝过程
存入Object表中
public Uri insert(Uri uri, ContentValues initialValues) //MediaProvider.java

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        int match = URI_MATCHER.match(uri);

        ArrayList<Long> notifyRowIds = new ArrayList<Long>();
        Uri newUri = insertInternal(uri, match, initialValues, notifyRowIds);
        if (uri != null) {
            if (uri.toString().startsWith("content://media/external/")) {
                notifyMtp(notifyRowIds);
            }
        }

        // do not signal notification for MTP objects.
        // we will signal instead after file transfer is successful.
        // object不会发送通知
        if (newUri != null && match != MTP_OBJECTS) {
            // Report a general change to the media provider.
            // We only report this to observers that are not looking at
            // this specific URI and its descendants, because they will
            // still see the following more-specific URI and thus get
            // redundant info (and not be able to know if there was just
            // the specific URI change or also some general change in the
            // parent URI).
            getContext().getContentResolver().notifyChange(uri, null, match != MEDIA_SCANNER
                    ? ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS : 0);
            // Also report the specific URIs that changed.
            if (match != MEDIA_SCANNER) {
                getContext().getContentResolver().notifyChange(newUri, null, 0);
            }
        }
        return newUri;
    }

private Uri insertInternal(Uri uri, int match, ContentValues initialValues, ...) //MediaProvider.java
private long insertFile(DatabaseHelper helper, Uri uri, ContentValues initialValues, ...) //MediaProvider.java
拷贝过程
MtpResponseCode MtpServer::doSendObject() //MtpServer.cpp
private void endSendObject(String path, int handle, int format,...) //MtpDatabase.java
public void scanMtpFile(String path, int objectHandle, int format) //MediaScanner.java

public void scanMtpFile(String path, int objectHandle, int format) {
        MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
        int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
        File file = new File(path);
        long lastModifiedSeconds = file.lastModified() / 1000;
        // 这里没有判别APK文件,将会返回,不会走到mClient.doScanFile,导致不会通知
        if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) &&
            !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType) &&
            !MediaFile.isDrmFileType(fileType)) {

            // no need to use the media scanner, but we need to update last modified and file size
            ContentValues values = new ContentValues();
            values.put(Files.FileColumns.SIZE, file.length());
            values.put(Files.FileColumns.DATE_MODIFIED, lastModifiedSeconds);
            try {
                String[] whereArgs = new String[] {  Integer.toString(objectHandle) };
                mMediaProvider.update(Files.getMtpObjectsUri(mVolumeName), values,
                        "_id=?", whereArgs);
            } catch (RemoteException e) {
                Log.e(TAG, "RemoteException in scanMtpFile", e);
            }
            return;
        }

        mMtpObjectHandle = objectHandle;
        Cursor fileList = null;
        try {
            if (MediaFile.isPlayListFileType(fileType)) {
                // build file cache so we can look up tracks in the playlist
                prescan(null, true);

                FileEntry entry = makeEntryFor(path);
                if (entry != null) {
                    fileList = mMediaProvider.query(mFilesUri,
                            FILES_PRESCAN_PROJECTION, null, null, null, null);
                    processPlayList(entry, fileList);
                }
            } else {
                // MTP will create a file entry for us so we don't want to do it in prescan
                prescan(path, false);

                // always scan the file, so we can return the content://media Uri for existing files
                mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(),
                    (format == MtpConstants.FORMAT_ASSOCIATION), true, isNoMediaPath(path));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
        } finally {
            mMtpObjectHandle = 0;
            if (fileList != null) {
                fileList.close();
            }
            releaseResources();
        }
    }

public Uri doScanFile(String path,...) //MediaScannerMyMediaScannerClient.java private Uri endFile(FileEntry entry,...) //MediaScannerMyMediaScannerClient.java
拷贝完成之后存入files表中
public Uri insert(Uri uri, ContentValues initialValues) //MediaProvider.java

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        int match = URI_MATCHER.match(uri);

        ArrayList<Long> notifyRowIds = new ArrayList<Long>();
        Uri newUri = insertInternal(uri, match, initialValues, notifyRowIds);
        if (uri != null) {
            if (uri.toString().startsWith("content://media/external/")) {
                notifyMtp(notifyRowIds);
            }
        }

        // do not signal notification for MTP objects.
        // we will signal instead after file transfer is successful.
        // 此时已经是file了,不是Object了,将会发送通知事件
        if (newUri != null && match != MTP_OBJECTS) {
            // Report a general change to the media provider.
            // We only report this to observers that are not looking at
            // this specific URI and its descendants, because they will
            // still see the following more-specific URI and thus get
            // redundant info (and not be able to know if there was just
            // the specific URI change or also some general change in the
            // parent URI).
            getContext().getContentResolver().notifyChange(uri, null, match != MEDIA_SCANNER
                    ? ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS : 0);
            // Also report the specific URIs that changed.
            if (match != MEDIA_SCANNER) {
                getContext().getContentResolver().notifyChange(newUri, null, 0);
            }
        }
        return newUri;
    }

2、修改方案
查找原因是因为在doSendObjectInfo的时候获取的format不正确

MtpResponseCode MtpServer::doSendObjectInfo() {
...
    // read only the fields we need
    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // storage ID
    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
    MtpObjectFormat format = temp16;//这里获取的format是0x3000,即MTP_FORMAT_UNDEFINED,未定义,导致后面不会执行mClient.doScanFile方法
    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;  // protection status
    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
    mSendObjectFileSize = temp32;
    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb format
    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb compressed size
    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb pix width
    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb pix height
    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image pix width
    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image pix height
    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image bit depth
    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // parent
    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // sequence number
    MtpStringBuffer name, created, modified;
    if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER;    // file name
    if (name.getCharCount() == 0) {
        ALOGE("empty name");
        return MTP_RESPONSE_INVALID_PARAMETER;
    }
    if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER;      // date created
    if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER;     // date modified
    // keywords follow
    //在这里做一个筛选,把format等于UNDEFINED,并且是APK文件重新赋值为新定义的APK的format
    if(format == MTP_FORMAT_UNDEFINED) {
        const char *fileName = (const char *)name;
        int len = strlen(fileName);
        if(len >= 4 && fileName[len-4] == '.' && (fileName[len-3] == 'a' || fileName[len-3] == 'A')
                    && (fileName[len-2] == 'p' || fileName[len-2] == 'P')
                    && (fileName[len-1] == 'k' || fileName[len-1] == 'K')) {
            format = MTP_FORMAT_APK;
        }
    }

    ALOGV("name: %s format: %04X\n", (const char *)name, format);
...
}

在frameworks/av/media/mtp/mtp.h中加入MTP_FORMAT_APK

#define MTP_FORMAT_UNDEFINED_DOCUMENT                   0xBA80
#define MTP_FORMAT_ABSTRACT_DOCUMENT                    0xBA81
#define MTP_FORMAT_XML_DOCUMENT                         0xBA82
#define MTP_FORMAT_MS_WORD_DOCUMENT                     0xBA83
#define MTP_FORMAT_MHT_COMPILED_HTML_DOCUMENT           0xBA84
#define MTP_FORMAT_MS_EXCEL_SPREADSHEET                 0xBA85
#define MTP_FORMAT_MS_POWERPOINT_PRESENTATION           0xBA86
#define MTP_FORMAT_APK                                  0xBA87

在frameworks/base/media/java/android/mtp/MtpConstants.java中加入对应java层的formot常量

/** Format code for undefined document files */
    public static final int FORMAT_UNDEFINED_DOCUMENT = 0xBA80;
    /** Format code for abstract documents */
    public static final int FORMAT_ABSTRACT_DOCUMENT = 0xBA81;
    /** Format code for XML documents */
    public static final int FORMAT_XML_DOCUMENT = 0xBA82;
    /** Format code for MS Word documents */
    public static final int FORMAT_MS_WORD_DOCUMENT = 0xBA83;
    /** Format code for MS Excel spreadsheets */
    public static final int FORMAT_MS_EXCEL_SPREADSHEET = 0xBA85;
    /** Format code for MS PowerPoint presentatiosn */
    public static final int FORMAT_MS_POWERPOINT_PRESENTATION = 0xBA86;
    public static final int FORMAT_APK = 0xBA87;

在frameworks/base/media/java/android/media/MediaFile.java新增APK FileType-MimeType-Format的关量表并定义file type

    ...
    public static final int FILE_TYPE_MS_POWERPOINT = 106;
    public static final int FILE_TYPE_ZIP           = 107;
    public static final int FILE_TYPE_APK           = 108;
    ...
    static {
        ...
        addFileType("ZIP", FILE_TYPE_ZIP, "application/zip");
        addFileType("MPG", FILE_TYPE_MP2PS, "video/mp2p");
        addFileType("MPEG", FILE_TYPE_MP2PS, "video/mp2p");
        addFileType("APK", FILE_TYPE_APK, "application/apk", MtpConstants.FORMAT_APK);
    }
    ...
上一篇下一篇

猜你喜欢

热点阅读