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

Commit 1afa40c3 authored by Tobias Thierer's avatar Tobias Thierer Committed by android-build-merger
Browse files

Move default MimeMap implementation to frameworks. am: 878c77b7 am: 2b754d1f am: effe42d0

am: 752d297a

Change-Id: I938962e186475a2cb403a1ded40379adcaeb5266
parents 736d858a 752d297a
Loading
Loading
Loading
Loading
+13 −1
Original line number Original line Diff line number Diff line
@@ -111,6 +111,14 @@ filegroup {
    path: "media/mca/filterpacks/java",
    path: "media/mca/filterpacks/java",
}
}


filegroup {
    name: "framework-mime-sources",
    srcs: [
        "mime/java/**/*.java",
    ],
    path: "mime/java",
}

filegroup {
filegroup {
    name: "framework-opengl-sources",
    name: "framework-opengl-sources",
    srcs: [
    srcs: [
@@ -176,6 +184,7 @@ filegroup {
        ":framework-mca-effect-sources",
        ":framework-mca-effect-sources",
        ":framework-mca-filterfw-sources",
        ":framework-mca-filterfw-sources",
        ":framework-mca-filterpacks-sources",
        ":framework-mca-filterpacks-sources",
        ":framework-mime-sources",
        ":framework-opengl-sources",
        ":framework-opengl-sources",
        ":framework-rs-sources",
        ":framework-rs-sources",
        ":framework-sax-sources",
        ":framework-sax-sources",
@@ -316,7 +325,10 @@ java_defaults {


    jarjar_rules: ":framework-jarjar-rules",
    jarjar_rules: ":framework-jarjar-rules",


    static_libs: ["framework-internal-utils"],
    static_libs: [
        "framework-internal-utils",
        "mimemap",
    ],


    dxflags: [
    dxflags: [
        "--core-library",
        "--core-library",
+11 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.UnsupportedAppUsage;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ActivityThread;
import android.app.ApplicationErrorReport;
import android.app.ApplicationErrorReport;
import android.content.type.MimeMapImpl;
import android.os.Build;
import android.os.Build;
import android.os.DeadObjectException;
import android.os.DeadObjectException;
import android.os.Debug;
import android.os.Debug;
@@ -33,6 +34,9 @@ import com.android.internal.logging.AndroidConfig;
import com.android.server.NetworkManagementSocketTagger;
import com.android.server.NetworkManagementSocketTagger;
import dalvik.system.RuntimeHooks;
import dalvik.system.RuntimeHooks;
import dalvik.system.VMRuntime;
import dalvik.system.VMRuntime;

import libcore.net.MimeMap;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Modifier;
@@ -199,6 +203,13 @@ public class RuntimeInit {
    public static void preForkInit() {
    public static void preForkInit() {
        if (DEBUG) Slog.d(TAG, "Entered preForkInit.");
        if (DEBUG) Slog.d(TAG, "Entered preForkInit.");
        RuntimeInit.enableDdms();
        RuntimeInit.enableDdms();
        /*
         * Replace libcore's minimal default mapping between MIME types and file
         * extensions with a mapping that's suitable for Android. Android's mapping
         * contains many more entries that are derived from IANA registrations but
         * with several customizations (extensions, overrides).
         */
        MimeMap.setDefault(MimeMapImpl.createDefaultInstance());
    }
    }


    @UnsupportedAppUsage
    @UnsupportedAppUsage

mime/Android.bp

0 → 100644
+43 −0
Original line number Original line Diff line number Diff line
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

java_library {
    name: "mimemap",
    visibility: [
        "//cts/tests/tests/mimemap:__subpackages__",
        "//frameworks/base:__subpackages__",
    ],

    srcs: [
        "java/android/content/type/MimeMapImpl.java",
    ],

    java_resources: [
        ":debian.mime.types",
        ":android.mime.types",
    ],

    sdk_version: "core_platform",
}

filegroup {
    name: "android.mime.types",
    visibility: [
        "//visibility:private",
    ],
    path: "java-res/",
    srcs: [
        "java-res/android.mime.types",
    ],
}
+146 −0
Original line number Original line Diff line number Diff line

###############################################################################
#
# Android-specific MIME type <-> extension mappings
#
# Each line below defines an mapping from one MIME type to the first of the
# listed extensions, and from listed extension back to the MIME type.
# A mapping overrides any previous mapping _from_ that same MIME type or
# extension (put() semantics), unless that MIME type / extension is prefixed with '?'
# (putIfAbsent() semantics).
#
#
###############################################################################
#
# EXAMPLES
#
# A line of the form:
#
#    ?mime ext1 ?ext2 ext3
#
# affects the current mappings along the lines of the following pseudo code:
#
#    mimeToExt.putIfAbsent("mime", "ext1");
#    extToMime.put("ext1", "mime");
#    extToMime.putIfAbsent("ext2", "mime");
#    extToMime.put("ext3", "mime");
#
# The line:
#
#     ?text/plain txt
#
# leaves any earlier mapping for "text/plain" untouched, or maps that MIME type
# to the file extension ".txt" if there is no earlier mapping. The line also
# sets the mapping from file extension ".txt" to be the MIME type "text/plain",
# regardless of whether a previous mapping existed.
#
###############################################################################


# File extensions that Android wants to override to point to the given MIME type.
#
# After processing a line of the form:
# ?<mimeType> <extension1> <extension2>
# If <mimeType> was not already mapped to an extension then it will be
# mapped to <extension1>.
# <extension1> and <extension2> are mapped (or remapped) to <mimeType>.

?application/epub+zip epub
?application/pkix-cert cer
?application/rss+xml rss
?application/vnd.android.ota ota
?application/vnd.apple.mpegurl m3u8
?application/vnd.ms-pki.stl stl
?application/vnd.ms-powerpoint pot
?application/vnd.ms-wpl wpl
?application/vnd.stardivision.impress sdp
?application/vnd.stardivision.writer vor
?application/vnd.youtube.yt yt
?application/x-android-drm-fl fl
?application/x-flac flac
?application/x-font pcf
?application/x-mpegurl m3u m3u8
?application/x-pem-file pem
?application/x-pkcs12 p12 pfx
?application/x-webarchive webarchive
?application/x-webarchive-xml webarchivexml
?application/x-x509-server-cert crt
?application/x-x509-user-cert crt

?audio/3gpp 3gpp
?audio/aac-adts aac
?audio/imelody imy
?audio/midi rtttl xmf
?audio/mobile-xmf mxmf
?audio/mp4 m4a
?audio/mpegurl m3u
?audio/sp-midi smf
?audio/x-matroska mka
?audio/x-pn-realaudio ra

?image/bmp bmp
?image/heic heic
?image/heic-sequence heics
?image/heif heif hif
?image/heif-sequence heifs
?image/ico cur
?image/webp webp
?image/x-adobe-dng dng
?image/x-fuji-raf raf
?image/x-icon ico
?image/x-nikon-nrw nrw
?image/x-panasonic-rw2 rw2
?image/x-pentax-pef pef
?image/x-samsung-srw srw
?image/x-sony-arw arw

?text/comma-separated-values csv
?text/plain diff po
?text/rtf rtf
?text/text phps
?text/xml xml
?text/x-vcard vcf

?video/3gpp2 3gpp2 3g2
?video/3gpp 3gpp
?video/avi avi
?video/m4v m4v
?video/mp2p mpeg
?video/mp2t m2ts mts
?video/mp2ts ts
?video/vnd.youtube.yt yt
?video/x-webex wrf

# Optional additions that should not override any previous mapping.

?application/x-wifi-config ?xml

# Special cases where Android has a strong opinion about mappings, so we
# define them very last and make them override in both directions (no "?").
#
# Lines here are of the form:
# <mimeType> <extension1> <extension2> ...
#
# After processing each line,
#   <mimeType> is mapped to <extension1>
#   <extension1>, <extension2>, ... are all mapped to <mimeType>
# This overrides any mappings for this <mimeType> / for these extensions
# that may have been defined earlier.

application/pgp-signature pgp
application/x-x509-ca-cert crt
audio/aac aac
audio/basic snd
audio/flac flac
audio/midi rtx
audio/mpeg mp3 m4a m4r
audio/x-mpegurl m3u m3u8
image/jpeg jpg
image/x-ms-bmp bmp
text/plain txt
text/x-c++hdr hpp
text/x-c++src cpp
video/3gpp 3gpp
video/mpeg mpeg
video/quicktime mov
video/x-matroska mkv
+194 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.content.type;

import libcore.net.MimeMap;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * Default implementation of {@link MimeMap}, a bidirectional mapping between
 * MIME types and file extensions.
 *
 * This default mapping is loaded from data files that start with some mappings
 * recognized by IANA plus some custom extensions and overrides.
 *
 * @hide
 */
public class MimeMapImpl extends MimeMap {

    /**
     * Creates and returns a new {@link MimeMapImpl} instance that implements.
     * Android's default mapping between MIME types and extensions.
     */
    public static MimeMapImpl createDefaultInstance() {
        return parseFromResources("/mime.types", "/android.mime.types");
    }

    private static final Pattern SPLIT_PATTERN = Pattern.compile("\\s+");

    /**
     * Note: These maps only contain lowercase keys/values, regarded as the
     * {@link #toLowerCase(String) canonical form}.
     *
     * <p>This is the case for both extensions and MIME types. The mime.types
     * data file contains examples of mixed-case MIME types, but some applications
     * use the lowercase version of these same types. RFC 2045 section 2 states
     * that MIME types are case insensitive.
     */
    private final Map<String, String> mMimeTypeToExtension;
    private final Map<String, String> mExtensionToMimeType;

    public MimeMapImpl(Map<String, String> mimeTypeToExtension,
            Map<String, String> extensionToMimeType) {
        this.mMimeTypeToExtension = new HashMap<>(mimeTypeToExtension);
        for (Map.Entry<String, String> entry : mimeTypeToExtension.entrySet()) {
            checkValidMimeType(entry.getKey());
            checkValidExtension(entry.getValue());
        }
        this.mExtensionToMimeType = new HashMap<>(extensionToMimeType);
        for (Map.Entry<String, String> entry : extensionToMimeType.entrySet()) {
            checkValidExtension(entry.getKey());
            checkValidMimeType(entry.getValue());
        }
    }

    private static void checkValidMimeType(String s) {
        if (MimeMap.isNullOrEmpty(s) || !s.equals(MimeMap.toLowerCase(s))) {
            throw new IllegalArgumentException("Invalid MIME type: " + s);
        }
    }

    private static void checkValidExtension(String s) {
        if (MimeMap.isNullOrEmpty(s) || !s.equals(MimeMap.toLowerCase(s))) {
            throw new IllegalArgumentException("Invalid extension: " + s);
        }
    }

    static MimeMapImpl parseFromResources(String... resourceNames) {
        Map<String, String> mimeTypeToExtension = new HashMap<>();
        Map<String, String> extensionToMimeType = new HashMap<>();
        for (String resourceName : resourceNames) {
            parseTypes(mimeTypeToExtension, extensionToMimeType, resourceName);
        }
        return new MimeMapImpl(mimeTypeToExtension, extensionToMimeType);
    }

    /**
     * An element of a *mime.types file: A MIME type or an extension, with an optional
     * prefix of "?" (if not overriding an earlier value).
     */
    private static class Element {
        public final boolean keepExisting;
        public final String s;

        Element(boolean keepExisting, String value) {
            this.keepExisting = keepExisting;
            this.s = toLowerCase(value);
            if (value.isEmpty()) {
                throw new IllegalArgumentException();
            }
        }

        public String toString() {
            return keepExisting ? ("?" + s) : s;
        }
    }

    private static String maybePut(Map<String, String> map, Element keyElement, String value) {
        if (keyElement.keepExisting) {
            return map.putIfAbsent(keyElement.s, value);
        } else {
            return map.put(keyElement.s, value);
        }
    }

    private static void parseTypes(Map<String, String> mimeTypeToExtension,
            Map<String, String> extensionToMimeType, String resource) {
        try (BufferedReader r = new BufferedReader(
                new InputStreamReader(MimeMapImpl.class.getResourceAsStream(resource)))) {
            String line;
            while ((line = r.readLine()) != null) {
                int commentPos = line.indexOf('#');
                if (commentPos >= 0) {
                    line = line.substring(0, commentPos);
                }
                line = line.trim();
                // The first time a MIME type is encountered it is mapped to the first extension
                // listed in its line. The first time an extension is encountered it is mapped
                // to the MIME type.
                //
                // When encountering a previously seen MIME type or extension, then by default
                // the later ones override earlier mappings (put() semantics); however if a MIME
                // type or extension is prefixed with '?' then any earlier mapping _from_ that
                // MIME type / extension is kept (putIfAbsent() semantics).
                final String[] split = SPLIT_PATTERN.split(line);
                if (split.length <= 1) {
                    // Need mimeType + at least one extension to make a mapping.
                    // "mime.types" files may also contain lines with just a mimeType without
                    // an extension but we skip them as they provide no mapping info.
                    continue;
                }
                List<Element> lineElements = new ArrayList<>(split.length);
                for (String s : split) {
                    boolean keepExisting = s.startsWith("?");
                    if (keepExisting) {
                        s = s.substring(1);
                    }
                    if (s.isEmpty()) {
                        throw new IllegalArgumentException("Invalid entry in '" + line + "'");
                    }
                    lineElements.add(new Element(keepExisting, s));
                }

                // MIME type -> first extension (one mapping)
                // This will override any earlier mapping from this MIME type to another
                // extension, unless this MIME type was prefixed with '?'.
                Element mimeElement = lineElements.get(0);
                List<Element> extensionElements = lineElements.subList(1, lineElements.size());
                String firstExtension = extensionElements.get(0).s;
                maybePut(mimeTypeToExtension, mimeElement, firstExtension);

                // extension -> MIME type (one or more mappings).
                // This will override any earlier mapping from this extension to another
                // MIME type, unless this extension was prefixed with '?'.
                for (Element extensionElement : extensionElements) {
                    maybePut(extensionToMimeType, extensionElement, mimeElement.s);
                }
            }
        } catch (IOException | RuntimeException e) {
            throw new RuntimeException("Failed to parse " + resource, e);
        }
    }

    @Override
    protected String guessExtensionFromLowerCaseMimeType(String mimeType) {
        return mMimeTypeToExtension.get(mimeType);
    }

    @Override
    protected String guessMimeTypeFromLowerCaseExtension(String extension) {
        return mExtensionToMimeType.get(extension);
    }
}