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

Commit 1af6a12e authored by Xin Li's avatar Xin Li Committed by Gerrit Code Review
Browse files

Merge "Merge RQ2A.210305.007"

parents eeb577dc e085f874
Loading
Loading
Loading
Loading
+46 −25
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;


import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;


import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.app.job.JobInfo;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivityManager.NetworkCallback;
@@ -85,9 +86,12 @@ public final class ConnectivityController extends RestrictingController implemen
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private final SparseArray<ArraySet<JobStatus>> mRequestedWhitelistJobs = new SparseArray<>();
    private final SparseArray<ArraySet<JobStatus>> mRequestedWhitelistJobs = new SparseArray<>();


    /** List of currently available networks. */
    /**
     * Set of currently available networks mapped to their latest network capabilities. Cache the
     * latest capabilities to avoid unnecessary calls into ConnectivityManager.
     */
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private final ArraySet<Network> mAvailableNetworks = new ArraySet<>();
    private final ArrayMap<Network, NetworkCapabilities> mAvailableNetworks = new ArrayMap<>();


    private static final int MSG_DATA_SAVER_TOGGLED = 0;
    private static final int MSG_DATA_SAVER_TOGGLED = 0;
    private static final int MSG_UID_RULES_CHANGES = 1;
    private static final int MSG_UID_RULES_CHANGES = 1;
@@ -164,9 +168,8 @@ public final class ConnectivityController extends RestrictingController implemen
    public boolean isNetworkAvailable(JobStatus job) {
    public boolean isNetworkAvailable(JobStatus job) {
        synchronized (mLock) {
        synchronized (mLock) {
            for (int i = 0; i < mAvailableNetworks.size(); ++i) {
            for (int i = 0; i < mAvailableNetworks.size(); ++i) {
                final Network network = mAvailableNetworks.valueAt(i);
                final Network network = mAvailableNetworks.keyAt(i);
                final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(
                final NetworkCapabilities capabilities = mAvailableNetworks.valueAt(i);
                        network);
                final boolean satisfied = isSatisfied(job, network, capabilities, mConstants);
                final boolean satisfied = isSatisfied(job, network, capabilities, mConstants);
                if (DEBUG) {
                if (DEBUG) {
                    Slog.v(TAG, "isNetworkAvailable(" + job + ") with network " + network
                    Slog.v(TAG, "isNetworkAvailable(" + job + ") with network " + network
@@ -424,9 +427,33 @@ public final class ConnectivityController extends RestrictingController implemen
        return false;
        return false;
    }
    }


    @Nullable
    private NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
        if (network == null) {
            return null;
        }
        synchronized (mLock) {
            // There is technically a race here if the Network object is reused. This can happen
            // only if that Network disconnects and the auto-incrementing network ID in
            // ConnectivityService wraps. This should no longer be a concern if/when we only make
            // use of asynchronous calls.
            if (mAvailableNetworks.get(network) != null) {
                return mAvailableNetworks.get(network);
            }

            // This should almost never happen because any time a new network connects, the
            // NetworkCallback would populate mAvailableNetworks. However, it's currently necessary
            // because we also call synchronous methods such as getActiveNetworkForUid.
            // TODO(134978280): remove after switching to callback-based APIs
            final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
            mAvailableNetworks.put(network, capabilities);
            return capabilities;
        }
    }

    private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
    private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
        final Network network = mConnManager.getActiveNetworkForUid(jobStatus.getSourceUid());
        final Network network = mConnManager.getActiveNetworkForUid(jobStatus.getSourceUid());
        final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
        final NetworkCapabilities capabilities = getNetworkCapabilities(network);
        return updateConstraintsSatisfied(jobStatus, network, capabilities);
        return updateConstraintsSatisfied(jobStatus, network, capabilities);
    }
    }


@@ -467,19 +494,13 @@ public final class ConnectivityController extends RestrictingController implemen
     */
     */
    private void updateTrackedJobs(int filterUid, Network filterNetwork) {
    private void updateTrackedJobs(int filterUid, Network filterNetwork) {
        synchronized (mLock) {
        synchronized (mLock) {
            // Since this is a really hot codepath, temporarily cache any
            // answers that we get from ConnectivityManager.
            final ArrayMap<Network, NetworkCapabilities> networkToCapabilities = new ArrayMap<>();

            boolean changed = false;
            boolean changed = false;
            if (filterUid == -1) {
            if (filterUid == -1) {
                for (int i = mTrackedJobs.size() - 1; i >= 0; i--) {
                for (int i = mTrackedJobs.size() - 1; i >= 0; i--) {
                    changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i),
                    changed |= updateTrackedJobsLocked(mTrackedJobs.valueAt(i), filterNetwork);
                            filterNetwork, networkToCapabilities);
                }
                }
            } else {
            } else {
                changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid),
                changed = updateTrackedJobsLocked(mTrackedJobs.get(filterUid), filterNetwork);
                        filterNetwork, networkToCapabilities);
            }
            }
            if (changed) {
            if (changed) {
                mStateChangedListener.onControllerStateChanged();
                mStateChangedListener.onControllerStateChanged();
@@ -487,18 +508,13 @@ public final class ConnectivityController extends RestrictingController implemen
        }
        }
    }
    }


    private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork,
    private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork) {
            ArrayMap<Network, NetworkCapabilities> networkToCapabilities) {
        if (jobs == null || jobs.size() == 0) {
        if (jobs == null || jobs.size() == 0) {
            return false;
            return false;
        }
        }


        final Network network = mConnManager.getActiveNetworkForUid(jobs.valueAt(0).getSourceUid());
        final Network network = mConnManager.getActiveNetworkForUid(jobs.valueAt(0).getSourceUid());
        NetworkCapabilities capabilities = networkToCapabilities.get(network);
        final NetworkCapabilities capabilities = getNetworkCapabilities(network);
        if (capabilities == null) {
            capabilities = mConnManager.getNetworkCapabilities(network);
            networkToCapabilities.put(network, capabilities);
        }
        final boolean networkMatch = (filterNetwork == null
        final boolean networkMatch = (filterNetwork == null
                || Objects.equals(filterNetwork, network));
                || Objects.equals(filterNetwork, network));


@@ -541,9 +557,9 @@ public final class ConnectivityController extends RestrictingController implemen
        @Override
        @Override
        public void onAvailable(Network network) {
        public void onAvailable(Network network) {
            if (DEBUG) Slog.v(TAG, "onAvailable: " + network);
            if (DEBUG) Slog.v(TAG, "onAvailable: " + network);
            synchronized (mLock) {
            // Documentation says not to call getNetworkCapabilities here but wait for
                mAvailableNetworks.add(network);
            // onCapabilitiesChanged instead.  onCapabilitiesChanged should be called immediately
            }
            // after this, so no need to update mAvailableNetworks here.
        }
        }


        @Override
        @Override
@@ -551,6 +567,9 @@ public final class ConnectivityController extends RestrictingController implemen
            if (DEBUG) {
            if (DEBUG) {
                Slog.v(TAG, "onCapabilitiesChanged: " + network);
                Slog.v(TAG, "onCapabilitiesChanged: " + network);
            }
            }
            synchronized (mLock) {
                mAvailableNetworks.put(network, capabilities);
            }
            updateTrackedJobs(-1, network);
            updateTrackedJobs(-1, network);
        }
        }


@@ -627,6 +646,8 @@ public final class ConnectivityController extends RestrictingController implemen
            pw.println("Available networks:");
            pw.println("Available networks:");
            pw.increaseIndent();
            pw.increaseIndent();
            for (int i = 0; i < mAvailableNetworks.size(); i++) {
            for (int i = 0; i < mAvailableNetworks.size(); i++) {
                pw.print(mAvailableNetworks.keyAt(i));
                pw.print(": ");
                pw.println(mAvailableNetworks.valueAt(i));
                pw.println(mAvailableNetworks.valueAt(i));
            }
            }
            pw.decreaseIndent();
            pw.decreaseIndent();
@@ -664,7 +685,7 @@ public final class ConnectivityController extends RestrictingController implemen
                    mRequestedWhitelistJobs.keyAt(i));
                    mRequestedWhitelistJobs.keyAt(i));
        }
        }
        for (int i = 0; i < mAvailableNetworks.size(); i++) {
        for (int i = 0; i < mAvailableNetworks.size(); i++) {
            Network network = mAvailableNetworks.valueAt(i);
            Network network = mAvailableNetworks.keyAt(i);
            if (network != null) {
            if (network != null) {
                network.dumpDebug(proto,
                network.dumpDebug(proto,
                        StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);
                        StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);
+24 −2
Original line number Original line Diff line number Diff line
@@ -44,7 +44,6 @@ java_library {
    libs: [
    libs: [
        "framework_media_annotation",
        "framework_media_annotation",
    ],
    ],

    static_libs: [
    static_libs: [
        "exoplayer2-extractor"
        "exoplayer2-extractor"
    ],
    ],
@@ -115,10 +114,33 @@ java_sdk_library {
    impl_library_visibility: ["//frameworks/av/apex:__subpackages__"],
    impl_library_visibility: ["//frameworks/av/apex:__subpackages__"],
}
}



java_library {
java_library {
    name: "framework_media_annotation",
    name: "framework_media_annotation",
    srcs: [":framework-media-annotation-srcs"],
    srcs: [":framework-media-annotation-srcs"],
    installable: false,
    installable: false,
    sdk_version: "core_current",
    sdk_version: "core_current",
}
}

cc_library_shared {
    name: "libmediaparser-jni",
    srcs: [
        "jni/android_media_MediaParserJNI.cpp",
    ],
    header_libs: ["jni_headers"],
    shared_libs: [
        "libandroid",
        "liblog",
        "libmediametrics",
    ],
    cflags: [
        "-Wall",
        "-Werror",
        "-Wno-unused-parameter",
        "-Wunreachable-code",
        "-Wunused",
    ],
    apex_available: [
        "com.android.media",
    ],
    min_sdk_version: "29",
}
+148 −11
Original line number Original line Diff line number Diff line
@@ -75,6 +75,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.UUID;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;


/**
/**
 * Parses media container formats and extracts contained media samples and metadata.
 * Parses media container formats and extracts contained media samples and metadata.
@@ -882,6 +884,7 @@ public final class MediaParser {
    // Private constants.
    // Private constants.


    private static final String TAG = "MediaParser";
    private static final String TAG = "MediaParser";
    private static final String JNI_LIBRARY_NAME = "mediaparser-jni";
    private static final Map<String, ExtractorFactory> EXTRACTOR_FACTORIES_BY_NAME;
    private static final Map<String, ExtractorFactory> EXTRACTOR_FACTORIES_BY_NAME;
    private static final Map<String, Class> EXPECTED_TYPE_BY_PARAMETER_NAME;
    private static final Map<String, Class> EXPECTED_TYPE_BY_PARAMETER_NAME;
    private static final String TS_MODE_SINGLE_PMT = "single_pmt";
    private static final String TS_MODE_SINGLE_PMT = "single_pmt";
@@ -889,6 +892,14 @@ public final class MediaParser {
    private static final String TS_MODE_HLS = "hls";
    private static final String TS_MODE_HLS = "hls";
    private static final int BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY = 6;
    private static final int BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY = 6;
    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
    private static final String MEDIAMETRICS_ELEMENT_SEPARATOR = "|";
    private static final int MEDIAMETRICS_MAX_STRING_SIZE = 200;
    private static final int MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH;
    /**
     * Intentional error introduced to reported metrics to prevent identification of the parsed
     * media. Note: Increasing this value may cause older hostside CTS tests to fail.
     */
    private static final float MEDIAMETRICS_DITHER = .02f;


    @IntDef(
    @IntDef(
            value = {
            value = {
@@ -920,7 +931,7 @@ public final class MediaParser {
            @NonNull @ParserName String name, @NonNull OutputConsumer outputConsumer) {
            @NonNull @ParserName String name, @NonNull OutputConsumer outputConsumer) {
        String[] nameAsArray = new String[] {name};
        String[] nameAsArray = new String[] {name};
        assertValidNames(nameAsArray);
        assertValidNames(nameAsArray);
        return new MediaParser(outputConsumer, /* sniff= */ false, name);
        return new MediaParser(outputConsumer, /* createdByName= */ true, name);
    }
    }


    /**
    /**
@@ -940,7 +951,7 @@ public final class MediaParser {
        if (parserNames.length == 0) {
        if (parserNames.length == 0) {
            parserNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]);
            parserNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]);
        }
        }
        return new MediaParser(outputConsumer, /* sniff= */ true, parserNames);
        return new MediaParser(outputConsumer, /* createdByName= */ false, parserNames);
    }
    }


    // Misc static methods.
    // Misc static methods.
@@ -1052,6 +1063,14 @@ public final class MediaParser {
    private long mPendingSeekPosition;
    private long mPendingSeekPosition;
    private long mPendingSeekTimeMicros;
    private long mPendingSeekTimeMicros;
    private boolean mLoggedSchemeInitDataCreationException;
    private boolean mLoggedSchemeInitDataCreationException;
    private boolean mReleased;

    // MediaMetrics fields.
    private final boolean mCreatedByName;
    private final SparseArray<Format> mTrackFormats;
    private String mLastObservedExceptionName;
    private long mDurationMillis;
    private long mResourceByteCount;


    // Public methods.
    // Public methods.


@@ -1166,11 +1185,15 @@ public final class MediaParser {
        if (mExtractorInput == null) {
        if (mExtractorInput == null) {
            // TODO: For efficiency, the same implementation should be used, by providing a
            // TODO: For efficiency, the same implementation should be used, by providing a
            // clearBuffers() method, or similar.
            // clearBuffers() method, or similar.
            long resourceLength = seekableInputReader.getLength();
            if (mResourceByteCount == 0) {
                // For resource byte count metric collection, we only take into account the length
                // of the first provided input reader.
                mResourceByteCount = resourceLength;
            }
            mExtractorInput =
            mExtractorInput =
                    new DefaultExtractorInput(
                    new DefaultExtractorInput(
                            mExoDataReader,
                            mExoDataReader, seekableInputReader.getPosition(), resourceLength);
                            seekableInputReader.getPosition(),
                            seekableInputReader.getLength());
        }
        }
        mExoDataReader.mInputReader = seekableInputReader;
        mExoDataReader.mInputReader = seekableInputReader;


@@ -1195,7 +1218,10 @@ public final class MediaParser {
                    }
                    }
                }
                }
                if (mExtractor == null) {
                if (mExtractor == null) {
                    throw UnrecognizedInputFormatException.createForExtractors(mParserNamesPool);
                    UnrecognizedInputFormatException exception =
                            UnrecognizedInputFormatException.createForExtractors(mParserNamesPool);
                    mLastObservedExceptionName = exception.getClass().getName();
                    throw exception;
                }
                }
                return true;
                return true;
            }
            }
@@ -1223,8 +1249,13 @@ public final class MediaParser {
        int result;
        int result;
        try {
        try {
            result = mExtractor.read(mExtractorInput, mPositionHolder);
            result = mExtractor.read(mExtractorInput, mPositionHolder);
        } catch (ParserException e) {
        } catch (Exception e) {
            throw new ParsingException(e);
            mLastObservedExceptionName = e.getClass().getName();
            if (e instanceof ParserException) {
                throw new ParsingException((ParserException) e);
            } else {
                throw e;
            }
        }
        }
        if (result == Extractor.RESULT_END_OF_INPUT) {
        if (result == Extractor.RESULT_END_OF_INPUT) {
            mExtractorInput = null;
            mExtractorInput = null;
@@ -1264,21 +1295,64 @@ public final class MediaParser {
     * invoked.
     * invoked.
     */
     */
    public void release() {
    public void release() {
        // TODO: Dump media metrics here.
        mExtractorInput = null;
        mExtractorInput = null;
        mExtractor = null;
        mExtractor = null;
        if (mReleased) {
            // Nothing to do.
            return;
        }
        mReleased = true;

        String trackMimeTypes = buildMediaMetricsString(format -> format.sampleMimeType);
        String trackCodecs = buildMediaMetricsString(format -> format.codecs);
        int videoWidth = -1;
        int videoHeight = -1;
        for (int i = 0; i < mTrackFormats.size(); i++) {
            Format format = mTrackFormats.valueAt(i);
            if (format.width != Format.NO_VALUE && format.height != Format.NO_VALUE) {
                videoWidth = format.width;
                videoHeight = format.height;
                break;
            }
        }

        String alteredParameters =
                String.join(
                        MEDIAMETRICS_ELEMENT_SEPARATOR,
                        mParserParameters.keySet().toArray(new String[0]));
        alteredParameters =
                alteredParameters.substring(
                        0,
                        Math.min(
                                alteredParameters.length(),
                                MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH));

        nativeSubmitMetrics(
                mParserName,
                mCreatedByName,
                String.join(MEDIAMETRICS_ELEMENT_SEPARATOR, mParserNamesPool),
                mLastObservedExceptionName,
                addDither(mResourceByteCount),
                addDither(mDurationMillis),
                trackMimeTypes,
                trackCodecs,
                alteredParameters,
                videoWidth,
                videoHeight);
    }
    }


    // Private methods.
    // Private methods.


    private MediaParser(OutputConsumer outputConsumer, boolean sniff, String... parserNamesPool) {
    private MediaParser(
            OutputConsumer outputConsumer, boolean createdByName, String... parserNamesPool) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
            throw new UnsupportedOperationException("Android version must be R or greater.");
            throw new UnsupportedOperationException("Android version must be R or greater.");
        }
        }
        mParserParameters = new HashMap<>();
        mParserParameters = new HashMap<>();
        mOutputConsumer = outputConsumer;
        mOutputConsumer = outputConsumer;
        mParserNamesPool = parserNamesPool;
        mParserNamesPool = parserNamesPool;
        mParserName = sniff ? PARSER_NAME_UNKNOWN : parserNamesPool[0];
        mCreatedByName = createdByName;
        mParserName = createdByName ? parserNamesPool[0] : PARSER_NAME_UNKNOWN;
        mPositionHolder = new PositionHolder();
        mPositionHolder = new PositionHolder();
        mExoDataReader = new InputReadingDataReader();
        mExoDataReader = new InputReadingDataReader();
        removePendingSeek();
        removePendingSeek();
@@ -1286,6 +1360,24 @@ public final class MediaParser {
        mScratchParsableByteArrayAdapter = new ParsableByteArrayAdapter();
        mScratchParsableByteArrayAdapter = new ParsableByteArrayAdapter();
        mSchemeInitDataConstructor = getSchemeInitDataConstructor();
        mSchemeInitDataConstructor = getSchemeInitDataConstructor();
        mMuxedCaptionFormats = new ArrayList<>();
        mMuxedCaptionFormats = new ArrayList<>();

        // MediaMetrics.
        mTrackFormats = new SparseArray<>();
        mLastObservedExceptionName = "";
        mDurationMillis = -1;
    }

    private String buildMediaMetricsString(Function<Format, String> formatFieldGetter) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < mTrackFormats.size(); i++) {
            if (i > 0) {
                stringBuilder.append(MEDIAMETRICS_ELEMENT_SEPARATOR);
            }
            String fieldValue = formatFieldGetter.apply(mTrackFormats.valueAt(i));
            stringBuilder.append(fieldValue != null ? fieldValue : "");
        }
        return stringBuilder.substring(
                0, Math.min(stringBuilder.length(), MEDIAMETRICS_MAX_STRING_SIZE));
    }
    }


    private void setMuxedCaptionFormats(List<MediaFormat> mediaFormats) {
    private void setMuxedCaptionFormats(List<MediaFormat> mediaFormats) {
@@ -1528,6 +1620,10 @@ public final class MediaParser {


        @Override
        @Override
        public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
        public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
            long durationUs = exoplayerSeekMap.getDurationUs();
            if (durationUs != C.TIME_UNSET) {
                mDurationMillis = C.usToMs(durationUs);
            }
            if (mExposeChunkIndexAsMediaFormat && exoplayerSeekMap instanceof ChunkIndex) {
            if (mExposeChunkIndexAsMediaFormat && exoplayerSeekMap instanceof ChunkIndex) {
                ChunkIndex chunkIndex = (ChunkIndex) exoplayerSeekMap;
                ChunkIndex chunkIndex = (ChunkIndex) exoplayerSeekMap;
                MediaFormat mediaFormat = new MediaFormat();
                MediaFormat mediaFormat = new MediaFormat();
@@ -1575,6 +1671,7 @@ public final class MediaParser {


        @Override
        @Override
        public void format(Format format) {
        public void format(Format format) {
            mTrackFormats.put(mTrackIndex, format);
            mOutputConsumer.onTrackDataFound(
            mOutputConsumer.onTrackDataFound(
                    mTrackIndex,
                    mTrackIndex,
                    new TrackData(
                    new TrackData(
@@ -2031,6 +2128,20 @@ public final class MediaParser {
        return new SeekPoint(exoPlayerSeekPoint.timeUs, exoPlayerSeekPoint.position);
        return new SeekPoint(exoPlayerSeekPoint.timeUs, exoPlayerSeekPoint.position);
    }
    }


    /**
     * Introduces random error to the given metric value in order to prevent the identification of
     * the parsed media.
     */
    private static long addDither(long value) {
        // Generate a random in [0, 1].
        double randomDither = ThreadLocalRandom.current().nextFloat();
        // Clamp the random number to [0, 2 * MEDIAMETRICS_DITHER].
        randomDither *= 2 * MEDIAMETRICS_DITHER;
        // Translate the random number to [1 - MEDIAMETRICS_DITHER, 1 + MEDIAMETRICS_DITHER].
        randomDither += 1 - MEDIAMETRICS_DITHER;
        return value != -1 ? (long) (value * randomDither) : -1;
    }

    private static void assertValidNames(@NonNull String[] names) {
    private static void assertValidNames(@NonNull String[] names) {
        for (String name : names) {
        for (String name : names) {
            if (!EXTRACTOR_FACTORIES_BY_NAME.containsKey(name)) {
            if (!EXTRACTOR_FACTORIES_BY_NAME.containsKey(name)) {
@@ -2070,9 +2181,26 @@ public final class MediaParser {
        }
        }
    }
    }


    // Native methods.

    private native void nativeSubmitMetrics(
            String parserName,
            boolean createdByName,
            String parserPool,
            String lastObservedExceptionName,
            long resourceByteCount,
            long durationMillis,
            String trackMimeTypes,
            String trackCodecs,
            String alteredParameters,
            int videoWidth,
            int videoHeight);

    // Static initialization.
    // Static initialization.


    static {
    static {
        System.loadLibrary(JNI_LIBRARY_NAME);

        // Using a LinkedHashMap to keep the insertion order when iterating over the keys.
        // Using a LinkedHashMap to keep the insertion order when iterating over the keys.
        LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>();
        LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>();
        // Parsers are ordered to match ExoPlayer's DefaultExtractorsFactory extractor ordering,
        // Parsers are ordered to match ExoPlayer's DefaultExtractorsFactory extractor ordering,
@@ -2125,6 +2253,15 @@ public final class MediaParser {
        // We do not check PARAMETER_EXPOSE_CAPTION_FORMATS here, and we do it in setParameters
        // We do not check PARAMETER_EXPOSE_CAPTION_FORMATS here, and we do it in setParameters
        // instead. Checking that the value is a List is insufficient to catch wrong parameter
        // instead. Checking that the value is a List is insufficient to catch wrong parameter
        // value types.
        // value types.
        int sumOfParameterNameLengths =
                expectedTypeByParameterName.keySet().stream()
                        .map(String::length)
                        .reduce(0, Integer::sum);
        sumOfParameterNameLengths += PARAMETER_EXPOSE_CAPTION_FORMATS.length();
        // Add space for any required separators.
        MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH =
                sumOfParameterNameLengths + expectedTypeByParameterName.size();

        EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName);
        EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName);
    }
    }
}
}
+92 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2020, 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.
 */

#include <jni.h>
#include <media/MediaMetrics.h>

#define JNI_FUNCTION(RETURN_TYPE, NAME, ...)                                               \
    extern "C" {                                                                           \
    JNIEXPORT RETURN_TYPE Java_android_media_MediaParser_##NAME(JNIEnv* env, jobject thiz, \
                                                                ##__VA_ARGS__);            \
    }                                                                                      \
    JNIEXPORT RETURN_TYPE Java_android_media_MediaParser_##NAME(JNIEnv* env, jobject thiz, \
                                                                ##__VA_ARGS__)

namespace {

constexpr char kMediaMetricsKey[] = "mediaparser";

constexpr char kAttributeParserName[] = "android.media.mediaparser.parserName";
constexpr char kAttributeCreatedByName[] = "android.media.mediaparser.createdByName";
constexpr char kAttributeParserPool[] = "android.media.mediaparser.parserPool";
constexpr char kAttributeLastException[] = "android.media.mediaparser.lastException";
constexpr char kAttributeResourceByteCount[] = "android.media.mediaparser.resourceByteCount";
constexpr char kAttributeDurationMillis[] = "android.media.mediaparser.durationMillis";
constexpr char kAttributeTrackMimeTypes[] = "android.media.mediaparser.trackMimeTypes";
constexpr char kAttributeTrackCodecs[] = "android.media.mediaparser.trackCodecs";
constexpr char kAttributeAlteredParameters[] = "android.media.mediaparser.alteredParameters";
constexpr char kAttributeVideoWidth[] = "android.media.mediaparser.videoWidth";
constexpr char kAttributeVideoHeight[] = "android.media.mediaparser.videoHeight";

// Util class to handle string resource management.
class JstringHandle {
public:
    JstringHandle(JNIEnv* env, jstring value) : mEnv(env), mJstringValue(value) {
        mCstringValue = env->GetStringUTFChars(value, /* isCopy= */ nullptr);
    }

    ~JstringHandle() {
        if (mCstringValue != nullptr) {
            mEnv->ReleaseStringUTFChars(mJstringValue, mCstringValue);
        }
    }

    [[nodiscard]] const char* value() const {
        return mCstringValue != nullptr ? mCstringValue : "";
    }

    JNIEnv* mEnv;
    jstring mJstringValue;
    const char* mCstringValue;
};

} // namespace

JNI_FUNCTION(void, nativeSubmitMetrics, jstring parserNameJstring, jboolean createdByName,
             jstring parserPoolJstring, jstring lastExceptionJstring, jlong resourceByteCount,
             jlong durationMillis, jstring trackMimeTypesJstring, jstring trackCodecsJstring,
             jstring alteredParameters, jint videoWidth, jint videoHeight) {
    mediametrics_handle_t item(mediametrics_create(kMediaMetricsKey));
    mediametrics_setCString(item, kAttributeParserName,
                            JstringHandle(env, parserNameJstring).value());
    mediametrics_setInt32(item, kAttributeCreatedByName, createdByName ? 1 : 0);
    mediametrics_setCString(item, kAttributeParserPool,
                            JstringHandle(env, parserPoolJstring).value());
    mediametrics_setCString(item, kAttributeLastException,
                            JstringHandle(env, lastExceptionJstring).value());
    mediametrics_setInt64(item, kAttributeResourceByteCount, resourceByteCount);
    mediametrics_setInt64(item, kAttributeDurationMillis, durationMillis);
    mediametrics_setCString(item, kAttributeTrackMimeTypes,
                            JstringHandle(env, trackMimeTypesJstring).value());
    mediametrics_setCString(item, kAttributeTrackCodecs,
                            JstringHandle(env, trackCodecsJstring).value());
    mediametrics_setCString(item, kAttributeAlteredParameters,
                            JstringHandle(env, alteredParameters).value());
    mediametrics_setInt32(item, kAttributeVideoWidth, videoWidth);
    mediametrics_setInt32(item, kAttributeVideoHeight, videoHeight);
    mediametrics_selfRecord(item);
    mediametrics_delete(item);
}
+14 −0
Original line number Original line Diff line number Diff line
@@ -364,6 +364,18 @@ public class AccessibilityServiceInfo implements Parcelable {
     */
     */
    public static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x0001000;
    public static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x0001000;


    /**
     * This flag requests that when when {@link #FLAG_REQUEST_MULTI_FINGER_GESTURES} is enabled,
     * two-finger passthrough gestures are re-enabled. Two-finger swipe gestures are not detected,
     * but instead passed through as one-finger gestures. In addition, three-finger swipes from the
     * bottom of the screen are not detected, and instead are passed through unchanged. If {@link
     * #FLAG_REQUEST_MULTI_FINGER_GESTURES} is disabled this flag has no effect.
     *
     * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
     * @hide
     */
    public static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x0002000;

    /** {@hide} */
    /** {@hide} */
    public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
    public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;


@@ -1261,6 +1273,8 @@ public class AccessibilityServiceInfo implements Parcelable {
                return "FLAG_SERVICE_HANDLES_DOUBLE_TAP";
                return "FLAG_SERVICE_HANDLES_DOUBLE_TAP";
            case FLAG_REQUEST_MULTI_FINGER_GESTURES:
            case FLAG_REQUEST_MULTI_FINGER_GESTURES:
                return "FLAG_REQUEST_MULTI_FINGER_GESTURES";
                return "FLAG_REQUEST_MULTI_FINGER_GESTURES";
            case FLAG_REQUEST_2_FINGER_PASSTHROUGH:
                return "FLAG_REQUEST_2_FINGER_PASSTHROUGH";
            case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
            case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
                return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
                return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
            case FLAG_REPORT_VIEW_IDS:
            case FLAG_REPORT_VIEW_IDS:
Loading