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

Commit 35654b61 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

More work on App Ops service.

Implemented reading and writing state to retain information
across boots, API to retrieve state from it, improved location
manager interaction to monitor both coarse and fine access
and only note operations when location data is being delivered
back to app (not when it is just registering to get the data at
some time in the future).

Also implement tracking of read/write ops on contacts and the
call log.  This involved tweaking the content provider protocol
to pass over the name of the calling package, and some
infrastructure in the ContentProvider transport to note incoming
calls with the app ops service.  The contacts provider and call
log provider turn this on for themselves.

This also implements some of the mechanics of being able to ignore
incoming provider calls...  all that is left are some new APIs for
the real content provider implementation to be involved with
providing the correct behavior for query() (return an empty
cursor with the right columns) and insert() (need to figure out
what URI to return).

Change-Id: I36ebbcd63dee58264a480f3d3786891ca7cbdb4c
parent 8a8b047f
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -358,7 +358,7 @@ public class Content {

        @Override
        public void onExecute(IContentProvider provider) throws Exception {
            provider.insert(mUri, mContentValues);
            provider.insert(null, mUri, mContentValues);
        }
    }

@@ -372,7 +372,7 @@ public class Content {

        @Override
        public void onExecute(IContentProvider provider) throws Exception {
            provider.delete(mUri, mWhere, null);
            provider.delete(null, mUri, mWhere, null);
        }
    }

@@ -389,7 +389,7 @@ public class Content {

        @Override
        public void onExecute(IContentProvider provider) throws Exception {
            Cursor cursor = provider.query(mUri, mProjection, mWhere, null, mSortOrder, null);
            Cursor cursor = provider.query(null, mUri, mProjection, mWhere, null, mSortOrder, null);
            if (cursor == null) {
                System.out.println("No result found.");
                return;
@@ -451,7 +451,7 @@ public class Content {

        @Override
        public void onExecute(IContentProvider provider) throws Exception {
            provider.update(mUri, mContentValues, mWhere, null);
            provider.update(null, mUri, mContentValues, mWhere, null);
        }
    }

+2 −2
Original line number Diff line number Diff line
@@ -180,7 +180,7 @@ public final class SettingsCmd {
        try {
            Bundle arg = new Bundle();
            arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
            Bundle b = provider.call(callGetCommand, key, arg);
            Bundle b = provider.call(null, callGetCommand, key, arg);
            if (b != null) {
                result = b.getPairValue();
            }
@@ -205,7 +205,7 @@ public final class SettingsCmd {
            Bundle arg = new Bundle();
            arg.putString(Settings.NameValueTable.VALUE, value);
            arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
            provider.call(callPutCommand, key, arg);
            provider.call(null, callPutCommand, key, arg);
        } catch (RemoteException e) {
            System.err.println("Can't set key " + key + " in " + table + " for user " + userHandle);
        }
+20 −0
Original line number Diff line number Diff line
/**
 * Copyright (c) 2013, 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.app;

parcelable AppOpsManager.PackageOps;
parcelable AppOpsManager.OpEntry;
+162 −4
Original line number Diff line number Diff line
@@ -18,7 +18,12 @@ package android.app;

import com.android.internal.app.IAppOpsService;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;

@@ -31,24 +36,177 @@ public class AppOpsManager {
    public static final int MODE_IGNORED = 1;
    public static final int MODE_ERRORED = 2;

    public static final int OP_LOCATION = 0;
    public static final int OP_GPS = 1;
    public static final int OP_VIBRATE = 2;
    public static final int OP_COARSE_LOCATION = 0;
    public static final int OP_FINE_LOCATION = 1;
    public static final int OP_GPS = 2;
    public static final int OP_VIBRATE = 3;
    public static final int OP_READ_CONTACTS = 4;
    public static final int OP_WRITE_CONTACTS = 5;
    public static final int OP_READ_CALL_LOG = 6;
    public static final int OP_WRITE_CALL_LOG = 7;

    public static String opToString(int op) {
        switch (op) {
            case OP_LOCATION: return "LOCATION";
            case OP_COARSE_LOCATION: return "COARSE_LOCATION";
            case OP_FINE_LOCATION: return "FINE_LOCATION";
            case OP_GPS: return "GPS";
            case OP_VIBRATE: return "VIBRATE";
            case OP_READ_CONTACTS: return "READ_CONTACTS";
            case OP_WRITE_CONTACTS: return "WRITE_CONTACTS";
            case OP_READ_CALL_LOG: return "READ_CALL_LOG";
            case OP_WRITE_CALL_LOG: return "WRITE_CALL_LOG";
            default: return "Unknown(" + op + ")";
        }
    }

    public static class PackageOps implements Parcelable {
        private final String mPackageName;
        private final int mUid;
        private final List<OpEntry> mEntries;

        public PackageOps(String packageName, int uid, List<OpEntry> entries) {
            mPackageName = packageName;
            mUid = uid;
            mEntries = entries;
        }

        public String getPackageName() {
            return mPackageName;
        }

        public int getUid() {
            return mUid;
        }

        public List<OpEntry> getOps() {
            return mEntries;
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(mPackageName);
            dest.writeInt(mUid);
            dest.writeInt(mEntries.size());
            for (int i=0; i<mEntries.size(); i++) {
                mEntries.get(i).writeToParcel(dest, flags);
            }
        }

        PackageOps(Parcel source) {
            mPackageName = source.readString();
            mUid = source.readInt();
            mEntries = new ArrayList<OpEntry>();
            final int N = source.readInt();
            for (int i=0; i<N; i++) {
                mEntries.add(OpEntry.CREATOR.createFromParcel(source));
            }
        }

        public static final Creator<PackageOps> CREATOR = new Creator<PackageOps>() {
            @Override public PackageOps createFromParcel(Parcel source) {
                return new PackageOps(source);
            }

            @Override public PackageOps[] newArray(int size) {
                return new PackageOps[size];
            }
        };
    }

    public static class OpEntry implements Parcelable {
        private final int mOp;
        private final long mTime;
        private final int mDuration;

        public OpEntry(int op, long time, int duration) {
            mOp = op;
            mTime = time;
            mDuration = duration;
        }

        public int getOp() {
            return mOp;
        }

        public long getTime() {
            return mTime;
        }

        public boolean isRunning() {
            return mDuration == -1;
        }

        public int getDuration() {
            return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration;
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(mOp);
            dest.writeLong(mTime);
            dest.writeInt(mDuration);
        }

        OpEntry(Parcel source) {
            mOp = source.readInt();
            mTime = source.readLong();
            mDuration = source.readInt();
        }

        public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
            @Override public OpEntry createFromParcel(Parcel source) {
                return new OpEntry(source);
            }

            @Override public OpEntry[] newArray(int size) {
                return new OpEntry[size];
            }
        };
    }

    public AppOpsManager(Context context, IAppOpsService service) {
        mContext = context;
        mService = service;
    }

    public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
        try {
            return mService.getPackagesForOps(ops);
        } catch (RemoteException e) {
        }
        return null;
    }

    public int checkOp(int op, int uid, String packageName) {
        try {
            int mode = mService.checkOperation(op, uid, packageName);
            if (mode == MODE_ERRORED) {
                throw new SecurityException("Operation not allowed");
            }
            return mode;
        } catch (RemoteException e) {
        }
        return MODE_IGNORED;
    }

    public int checkOpNoThrow(int op, int uid, String packageName) {
        try {
            return mService.checkOperation(op, uid, packageName);
        } catch (RemoteException e) {
        }
        return MODE_IGNORED;
    }

    public int noteOp(int op, int uid, String packageName) {
        try {
            int mode = mService.noteOperation(op, uid, packageName);
+3 −1
Original line number Diff line number Diff line
@@ -623,7 +623,9 @@ class ContextImpl extends Context {
        if (mPackageInfo != null) {
            return mPackageInfo.getPackageName();
        }
        throw new RuntimeException("Not supported in system context");
        // No mPackageInfo means this is a Context for the system itself,
        // and this here is its name.
        return "android";
    }

    @Override
Loading