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

Commit bffd2508 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Translate selection arguments that are paths.

Also migrate MediaProvider logging to more general-purpose location
on the ContentProvider.Transport, where we can log exact input/output
values to aid debugging.

Bug: 124347872
Test: manual
Change-Id: I6aba60879ded4e0892d2d1cdd717c23cebaaabd8
parent 7b1a7b37
Loading
Loading
Loading
Loading
+59 −19
Original line number Original line Diff line number Diff line
@@ -209,9 +209,10 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
     * @hide
     * @hide
     */
     */
    class Transport extends ContentProviderNative {
    class Transport extends ContentProviderNative {
        AppOpsManager mAppOpsManager = null;
        volatile AppOpsManager mAppOpsManager = null;
        int mReadOp = AppOpsManager.OP_NONE;
        volatile int mReadOp = AppOpsManager.OP_NONE;
        int mWriteOp = AppOpsManager.OP_NONE;
        volatile int mWriteOp = AppOpsManager.OP_NONE;
        volatile ContentInterface mInterface = ContentProvider.this;


        ContentProvider getContentProvider() {
        ContentProvider getContentProvider() {
            return ContentProvider.this;
            return ContentProvider.this;
@@ -245,9 +246,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
                Cursor cursor;
                Cursor cursor;
                final String original = setCallingPackage(callingPkg);
                final String original = setCallingPackage(callingPkg);
                try {
                try {
                    cursor = ContentProvider.this.query(
                    cursor = mInterface.query(
                            uri, projection, queryArgs,
                            uri, projection, queryArgs,
                            CancellationSignal.fromTransport(cancellationSignal));
                            CancellationSignal.fromTransport(cancellationSignal));
                } catch (RemoteException e) {
                    throw e.rethrowAsRuntimeException();
                } finally {
                } finally {
                    setCallingPackage(original);
                    setCallingPackage(original);
                }
                }
@@ -261,9 +264,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "query");
            Trace.traceBegin(TRACE_TAG_DATABASE, "query");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return ContentProvider.this.query(
                return mInterface.query(
                        uri, projection, queryArgs,
                        uri, projection, queryArgs,
                        CancellationSignal.fromTransport(cancellationSignal));
                        CancellationSignal.fromTransport(cancellationSignal));
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -277,7 +282,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            uri = maybeGetUriWithoutUserId(uri);
            uri = maybeGetUriWithoutUserId(uri);
            Trace.traceBegin(TRACE_TAG_DATABASE, "getType");
            Trace.traceBegin(TRACE_TAG_DATABASE, "getType");
            try {
            try {
                return ContentProvider.this.getType(uri);
                return mInterface.getType(uri);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
            }
            }
@@ -299,7 +306,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "insert");
            Trace.traceBegin(TRACE_TAG_DATABASE, "insert");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return maybeAddUserId(ContentProvider.this.insert(uri, initialValues), userId);
                return maybeAddUserId(mInterface.insert(uri, initialValues), userId);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -316,7 +325,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "bulkInsert");
            Trace.traceBegin(TRACE_TAG_DATABASE, "bulkInsert");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return ContentProvider.this.bulkInsert(uri, initialValues);
                return mInterface.bulkInsert(uri, initialValues);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -357,7 +368,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "applyBatch");
            Trace.traceBegin(TRACE_TAG_DATABASE, "applyBatch");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                ContentProviderResult[] results = ContentProvider.this.applyBatch(authority,
                ContentProviderResult[] results = mInterface.applyBatch(authority,
                        operations);
                        operations);
                if (results != null) {
                if (results != null) {
                    for (int i = 0; i < results.length ; i++) {
                    for (int i = 0; i < results.length ; i++) {
@@ -368,6 +379,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
                    }
                    }
                }
                }
                return results;
                return results;
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -384,7 +397,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "delete");
            Trace.traceBegin(TRACE_TAG_DATABASE, "delete");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return ContentProvider.this.delete(uri, selection, selectionArgs);
                return mInterface.delete(uri, selection, selectionArgs);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -402,7 +417,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "update");
            Trace.traceBegin(TRACE_TAG_DATABASE, "update");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return ContentProvider.this.update(uri, values, selection, selectionArgs);
                return mInterface.update(uri, values, selection, selectionArgs);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -419,8 +436,10 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "openFile");
            Trace.traceBegin(TRACE_TAG_DATABASE, "openFile");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return ContentProvider.this.openFile(
                return mInterface.openFile(
                        uri, mode, CancellationSignal.fromTransport(cancellationSignal));
                        uri, mode, CancellationSignal.fromTransport(cancellationSignal));
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -437,8 +456,10 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "openAssetFile");
            Trace.traceBegin(TRACE_TAG_DATABASE, "openAssetFile");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return ContentProvider.this.openAssetFile(
                return mInterface.openAssetFile(
                        uri, mode, CancellationSignal.fromTransport(cancellationSignal));
                        uri, mode, CancellationSignal.fromTransport(cancellationSignal));
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -453,7 +474,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "call");
            Trace.traceBegin(TRACE_TAG_DATABASE, "call");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return ContentProvider.this.call(authority, method, arg, extras);
                return mInterface.call(authority, method, arg, extras);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -467,7 +490,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            uri = maybeGetUriWithoutUserId(uri);
            uri = maybeGetUriWithoutUserId(uri);
            Trace.traceBegin(TRACE_TAG_DATABASE, "getStreamTypes");
            Trace.traceBegin(TRACE_TAG_DATABASE, "getStreamTypes");
            try {
            try {
                return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter);
                return mInterface.getStreamTypes(uri, mimeTypeFilter);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
            }
            }
@@ -483,8 +508,10 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile");
            Trace.traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return ContentProvider.this.openTypedAssetFile(
                return mInterface.openTypedAssetFile(
                        uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
                        uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -507,7 +534,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "canonicalize");
            Trace.traceBegin(TRACE_TAG_DATABASE, "canonicalize");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return maybeAddUserId(ContentProvider.this.canonicalize(uri), userId);
                return maybeAddUserId(mInterface.canonicalize(uri), userId);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -525,7 +554,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "uncanonicalize");
            Trace.traceBegin(TRACE_TAG_DATABASE, "uncanonicalize");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return maybeAddUserId(ContentProvider.this.uncanonicalize(uri), userId);
                return maybeAddUserId(mInterface.uncanonicalize(uri), userId);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
                Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -543,7 +574,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
            Trace.traceBegin(TRACE_TAG_DATABASE, "refresh");
            Trace.traceBegin(TRACE_TAG_DATABASE, "refresh");
            final String original = setCallingPackage(callingPkg);
            final String original = setCallingPackage(callingPkg);
            try {
            try {
                return ContentProvider.this.refresh(uri, args,
                return mInterface.refresh(uri, args,
                        CancellationSignal.fromTransport(cancellationSignal));
                        CancellationSignal.fromTransport(cancellationSignal));
            } finally {
            } finally {
                setCallingPackage(original);
                setCallingPackage(original);
@@ -986,6 +1017,15 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
        return mTransport.mAppOpsManager;
        return mTransport.mAppOpsManager;
    }
    }


    /** @hide */
    public final void setTransportLoggingEnabled(boolean enabled) {
        if (enabled) {
            mTransport.mInterface = new LoggingContentInterface(getClass().getSimpleName(), this);
        } else {
            mTransport.mInterface = this;
        }
    }

    /**
    /**
     * Implement this to initialize your content provider on startup.
     * Implement this to initialize your content provider on startup.
     * This method is called for all registered content providers on the
     * This method is called for all registered content providers on the
+199 −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;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * Instance of {@link ContentInterface} that logs all inputs and outputs while
 * delegating to another {@link ContentInterface}.
 *
 * @hide
 */
public class LoggingContentInterface implements ContentInterface {
    private final String tag;
    private final ContentInterface delegate;

    public LoggingContentInterface(String tag, ContentInterface delegate) {
        this.tag = tag;
        this.delegate = delegate;
    }

    private void log(String method, Object res, Object... args) {
        // First, force-unparcel any bundles so we can log them
        for (Object arg : args) {
            if (arg instanceof Bundle) {
                ((Bundle) arg).size();
            }
        }

        final StringBuilder sb = new StringBuilder();
        sb.append("callingUid=").append(Binder.getCallingUid()).append(' ');
        sb.append(method);
        sb.append('(').append(deepToString(args)).append(')');
        if (res instanceof Cursor) {
            sb.append('\n');
            DatabaseUtils.dumpCursor((Cursor) res, sb);
        } else {
            sb.append(" = ").append(deepToString(res));
        }
        Log.v(tag, sb.toString());
    }

    private String deepToString(Object value) {
        if (value != null && value.getClass().isArray()) {
            return Arrays.deepToString((Object[]) value);
        } else {
            return String.valueOf(value);
        }
    }

    @Override
    public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
            @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)
            throws RemoteException {
        final Cursor res = delegate.query(uri, projection, queryArgs, cancellationSignal);
        log("query", res, uri, projection, queryArgs, cancellationSignal);
        return res;
    }

    @Override
    public @Nullable String getType(@NonNull Uri uri) throws RemoteException {
        final String res = delegate.getType(uri);
        log("getType", res, uri);
        return res;
    }

    @Override
    public @Nullable String[] getStreamTypes(@NonNull Uri uri, @NonNull String mimeTypeFilter)
            throws RemoteException {
        final String[] res = delegate.getStreamTypes(uri, mimeTypeFilter);
        log("getStreamTypes", res, uri, mimeTypeFilter);
        return res;
    }

    @Override
    public @Nullable Uri canonicalize(@NonNull Uri uri) throws RemoteException {
        final Uri res = delegate.canonicalize(uri);
        log("canonicalize", res, uri);
        return res;
    }

    @Override
    public @Nullable Uri uncanonicalize(@NonNull Uri uri) throws RemoteException {
        final Uri res = delegate.uncanonicalize(uri);
        log("uncanonicalize", res, uri);
        return res;
    }

    @Override
    public boolean refresh(@NonNull Uri uri, @Nullable Bundle args,
            @Nullable CancellationSignal cancellationSignal) throws RemoteException {
        final boolean res = delegate.refresh(uri, args, cancellationSignal);
        log("refresh", res, uri, args, cancellationSignal);
        return res;
    }

    @Override
    public @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues initialValues)
            throws RemoteException {
        final Uri res = delegate.insert(uri, initialValues);
        log("insert", res, uri, initialValues);
        return res;
    }

    @Override
    public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] initialValues)
            throws RemoteException {
        final int res = delegate.bulkInsert(uri, initialValues);
        log("bulkInsert", res, uri, initialValues);
        return res;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection,
            @Nullable String[] selectionArgs) throws RemoteException {
        final int res = delegate.delete(uri, selection, selectionArgs);
        log("delete", res, uri, selection, selectionArgs);
        return res;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
            @Nullable String[] selectionArgs) throws RemoteException {
        final int res = delegate.update(uri, values, selection, selectionArgs);
        log("update", res, uri, values, selection, selectionArgs);
        return res;
    }

    @Override
    public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode,
            @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
        final ParcelFileDescriptor res = delegate.openFile(uri, mode, signal);
        log("openFile", res, uri, mode, signal);
        return res;
    }

    @Override
    public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode,
            @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
        final AssetFileDescriptor res = delegate.openAssetFile(uri, mode, signal);
        log("openAssetFile", res, uri, mode, signal);
        return res;
    }

    @Override
    public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
            @NonNull String mimeTypeFilter, @Nullable Bundle opts,
            @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
        final AssetFileDescriptor res = delegate.openTypedAssetFile(uri, mimeTypeFilter, opts, signal);
        log("openTypedAssetFile", res, uri, mimeTypeFilter, opts, signal);
        return res;
    }

    @Override
    public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
            @NonNull ArrayList<ContentProviderOperation> operations)
            throws RemoteException, OperationApplicationException {
        final ContentProviderResult[] res = delegate.applyBatch(authority, operations);
        log("applyBatch", res, authority, operations);
        return res;
    }

    @Override
    public @Nullable Bundle call(@NonNull String authority, @NonNull String method,
            @Nullable String arg, @Nullable Bundle extras) throws RemoteException {
        final Bundle res = delegate.call(authority, method, arg, extras);
        log("call", res, authority, method, arg, extras);
        return res;
    }
}
+4 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,9 @@ package android.util;
import libcore.util.EmptyArray;
import libcore.util.EmptyArray;


import android.annotation.UnsupportedAppUsage;
import android.annotation.UnsupportedAppUsage;

import com.android.internal.util.ArrayUtils;

import java.util.Collection;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.ConcurrentModificationException;
import java.util.Map;
import java.util.Map;
@@ -816,7 +819,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {
            buffer.append('=');
            buffer.append('=');
            Object value = valueAt(i);
            Object value = valueAt(i);
            if (value != this) {
            if (value != this) {
                buffer.append(value);
                buffer.append(ArrayUtils.deepToString(value));
            } else {
            } else {
                buffer.append("(this Map)");
                buffer.append("(this Map)");
            }
            }
+26 −0
Original line number Original line Diff line number Diff line
@@ -712,4 +712,30 @@ public class ArrayUtils {
        }
        }
        return null;
        return null;
    }
    }

    public static String deepToString(Object value) {
        if (value != null && value.getClass().isArray()) {
            if (value.getClass() == boolean[].class) {
                return Arrays.toString((boolean[]) value);
            } else if (value.getClass() == byte[].class) {
                return Arrays.toString((byte[]) value);
            } else if (value.getClass() == char[].class) {
                return Arrays.toString((char[]) value);
            } else if (value.getClass() == double[].class) {
                return Arrays.toString((double[]) value);
            } else if (value.getClass() == float[].class) {
                return Arrays.toString((float[]) value);
            } else if (value.getClass() == int[].class) {
                return Arrays.toString((int[]) value);
            } else if (value.getClass() == long[].class) {
                return Arrays.toString((long[]) value);
            } else if (value.getClass() == short[].class) {
                return Arrays.toString((short[]) value);
            } else {
                return Arrays.deepToString((Object[]) value);
            }
        } else {
            return String.valueOf(value);
        }
    }
}
}