美文网首页
[MediaProvider]MTP拷贝APK文件Observe

[MediaProvider]MTP拷贝APK文件Observe

作者: Weller0 | 来源:发表于2018-09-26 17:52 被阅读0次

    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);
        }
        ...
    

    相关文章

      网友评论

          本文标题:[MediaProvider]MTP拷贝APK文件Observe

          本文链接:https://www.haomeiwen.com/subject/clhjoftx.html