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

Commit 628d2e68 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Redact location Exif tags when no permission."

parents 8dfdd617 cb394993
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -37297,6 +37297,7 @@ package android.provider {
    method public static java.lang.String getVolumeName(android.net.Uri);
    method public static android.provider.MediaStore.PendingSession openPending(android.content.Context, android.net.Uri);
    method public static android.net.Uri setIncludePending(android.net.Uri);
    method public static android.net.Uri setRequireOriginal(android.net.Uri);
    field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
    field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
    field public static final java.lang.String ACTION_REVIEW = "android.provider.action.REVIEW";
+4 −1
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ public class Content {
                    + "  <BINDING> binds a typed value to a column and is formatted:\n"
                    + "  <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
                    + "  <TYPE> specifies data type such as:\n"
                    + "  b - boolean, s - string, i - integer, l - long, f - float, d - double\n"
                    + "  b - boolean, s - string, i - integer, l - long, f - float, d - double, n - null\n"
                    + "  Note: Omit the value for passing an empty string, e.g column:s:\n"
                    + "  Example:\n"
                    + "  # Add \"new_setting\" secure setting with value \"new_value\".\n"
@@ -153,6 +153,7 @@ public class Content {
        private static final String TYPE_LONG = "l";
        private static final String TYPE_FLOAT = "f";
        private static final String TYPE_DOUBLE = "d";
        private static final String TYPE_NULL = "n";
        private static final String COLON = ":";
        private static final String ARGUMENT_PREFIX = "--";

@@ -410,6 +411,8 @@ public class Content {
                values.put(column, Long.parseLong(value));
            } else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) {
                values.put(column, Double.parseDouble(value));
            } else if (TYPE_NULL.equalsIgnoreCase(type)) {
                values.putNull(column);
            } else {
                throw new IllegalArgumentException("Unsupported type: " + type);
            }
+10 −8
Original line number Diff line number Diff line
@@ -17,12 +17,6 @@
package android.os;

import static android.system.OsConstants.AF_UNIX;
import static android.system.OsConstants.O_APPEND;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_RDWR;
import static android.system.OsConstants.O_TRUNC;
import static android.system.OsConstants.O_WRONLY;
import static android.system.OsConstants.SEEK_SET;
import static android.system.OsConstants.SOCK_SEQPACKET;
import static android.system.OsConstants.SOCK_STREAM;
@@ -254,8 +248,16 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
    }

    /** {@hide} */
    public static ParcelFileDescriptor fromFd(
            FileDescriptor fd, Handler handler, final OnCloseListener listener) throws IOException {
    public static ParcelFileDescriptor fromPfd(ParcelFileDescriptor pfd, Handler handler,
            final OnCloseListener listener) throws IOException {
        final FileDescriptor original = new FileDescriptor();
        original.setInt$(pfd.detachFd());
        return fromFd(original, handler, listener);
    }

    /** {@hide} */
    public static ParcelFileDescriptor fromFd(FileDescriptor fd, Handler handler,
            final OnCloseListener listener) throws IOException {
        if (handler == null) {
            throw new IllegalArgumentException("Handler must not be null");
        }
+76 −10
Original line number Diff line number Diff line
@@ -20,15 +20,18 @@ import android.content.Context;
import android.os.storage.StorageManager;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;

import libcore.io.IoUtils;
import libcore.util.EmptyArray;

import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Arrays;

/**
 * Variant of {@link FileDescriptor} that allows its creator to specify regions
@@ -40,20 +43,21 @@ public class RedactingFileDescriptor {
    private static final String TAG = "RedactingFileDescriptor";
    private static final boolean DEBUG = true;

    private final long[] mRedactRanges;
    private volatile long[] mRedactRanges;

    private FileDescriptor mInner = null;
    private ParcelFileDescriptor mOuter = null;

    private RedactingFileDescriptor(Context context, File file, long[] redactRanges)
    private RedactingFileDescriptor(Context context, File file, int mode, long[] redactRanges)
            throws IOException {
        mRedactRanges = checkRangesArgument(redactRanges);

        try {
            try {
                mInner = Os.open(file.getAbsolutePath(), OsConstants.O_RDONLY, 0);
                mInner = Os.open(file.getAbsolutePath(),
                        FileUtils.translateModePfdToPosix(mode), 0);
                mOuter = context.getSystemService(StorageManager.class)
                        .openProxyFileDescriptor(ParcelFileDescriptor.MODE_READ_ONLY, mCallback);
                        .openProxyFileDescriptor(mode, mCallback);
            } catch (ErrnoException e) {
                throw e.rethrowAsIOException();
            }
@@ -78,16 +82,61 @@ public class RedactingFileDescriptor {

    /**
     * Open the given {@link File} and returns a {@link ParcelFileDescriptor}
     * that offers a redacted, read-only view of the underlying data.
     * that offers a redacted view of the underlying data. If a redacted region
     * is written to, the newly written data can be read back correctly instead
     * of continuing to be redacted.
     *
     * @param file The underlying file to open.
     * @param mode The {@link ParcelFileDescriptor} mode to open with.
     * @param redactRanges List of file offsets that should be redacted, stored
     *            as {@code [start1, end1, start2, end2, ...]}. Start values are
     *            inclusive and end values are exclusive.
     */
    public static ParcelFileDescriptor open(Context context, File file, long[] redactRanges)
            throws IOException {
        return new RedactingFileDescriptor(context, file, redactRanges).mOuter;
    public static ParcelFileDescriptor open(Context context, File file, int mode,
            long[] redactRanges) throws IOException {
        return new RedactingFileDescriptor(context, file, mode, redactRanges).mOuter;
    }

    /**
     * Update the given ranges argument to remove any references to the given
     * offset and length. This is typically used when a caller has written over
     * a previously redacted region.
     */
    @VisibleForTesting
    public static long[] removeRange(long[] ranges, long start, long end) {
        if (start == end) {
            return ranges;
        } else if (start > end) {
            throw new IllegalArgumentException();
        }

        long[] res = EmptyArray.LONG;
        for (int i = 0; i < ranges.length; i += 2) {
            if (start <= ranges[i] && end >= ranges[i + 1]) {
                // Range entirely covered; remove it
            } else if (start >= ranges[i] && end <= ranges[i + 1]) {
                // Range partially covered; punch a hole
                res = Arrays.copyOf(res, res.length + 4);
                res[res.length - 4] = ranges[i];
                res[res.length - 3] = start;
                res[res.length - 2] = end;
                res[res.length - 1] = ranges[i + 1];
            } else {
                // Range might covered; adjust edges if needed
                res = Arrays.copyOf(res, res.length + 2);
                if (end >= ranges[i] && end <= ranges[i + 1]) {
                    res[res.length - 2] = Math.max(ranges[i], end);
                } else {
                    res[res.length - 2] = ranges[i];
                }
                if (start >= ranges[i] && start <= ranges[i + 1]) {
                    res[res.length - 1] = Math.min(ranges[i + 1], start);
                } else {
                    res[res.length - 1] = ranges[i + 1];
                }
            }
        }
        return res;
    }

    private final ProxyFileDescriptorCallback mCallback = new ProxyFileDescriptorCallback() {
@@ -126,7 +175,24 @@ public class RedactingFileDescriptor {

        @Override
        public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
            throw new ErrnoException(TAG, OsConstants.EBADF);
            int n = 0;
            while (n < size) {
                try {
                    final int res = Os.pwrite(mInner, data, n, size - n, offset + n);
                    if (res == 0) {
                        break;
                    } else {
                        n += res;
                    }
                } catch (InterruptedIOException e) {
                    n += e.bytesTransferred;
                }
            }

            // Clear any relevant redaction ranges before returning, since the
            // writer should have access to see the data they just overwrote
            mRedactRanges = removeRange(mRedactRanges, offset, offset + n);
            return n;
        }

        @Override
+20 −0
Original line number Diff line number Diff line
@@ -121,6 +121,8 @@ public final class MediaStore {
    public static final String PARAM_INCLUDE_PENDING = "includePending";
    /** {@hide} */
    public static final String PARAM_PROGRESS = "progress";
    /** {@hide} */
    public static final String PARAM_REQUIRE_ORIGINAL = "requireOriginal";

    /**
     * Activity Action: Launch a music player.
@@ -477,6 +479,24 @@ public final class MediaStore {
        return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_PENDING, "1").build();
    }

    /**
     * Update the given {@link Uri} to indicate that the caller requires the
     * original file contents when calling
     * {@link ContentResolver#openFileDescriptor(Uri, String)}.
     * <p>
     * This can be useful when the caller wants to ensure they're backing up the
     * exact bytes of the underlying media, without any Exif redaction being
     * performed.
     * <p>
     * If the original file contents cannot be provided, a
     * {@link UnsupportedOperationException} will be thrown when the returned
     * {@link Uri} is used, such as when the caller doesn't hold
     * {@link android.Manifest.permission#ACCESS_MEDIA_LOCATION}.
     */
    public static @NonNull Uri setRequireOriginal(@NonNull Uri uri) {
        return uri.buildUpon().appendQueryParameter(PARAM_REQUIRE_ORIGINAL, "1").build();
    }

    /**
     * Create a new pending media item using the given parameters. Pending items
     * are expected to have a short lifetime, and owners should either
Loading