UriPermission.java revision 9158825f9c41869689d6b1786d7c7aa8bdd524ce
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import android.content.Intent;
20import android.net.Uri;
21import android.os.UserHandle;
22import android.util.Log;
23
24import com.google.android.collect.Sets;
25
26import java.io.PrintWriter;
27import java.util.Comparator;
28import java.util.HashSet;
29
30/**
31 * Description of a permission granted to an app to access a particular URI.
32 *
33 * CTS tests for this functionality can be run with "runtest cts-appsecurity".
34 *
35 * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
36 *      src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
37 */
38final class UriPermission {
39    private static final String TAG = "UriPermission";
40
41    public static final int STRENGTH_NONE = 0;
42    public static final int STRENGTH_OWNED = 1;
43    public static final int STRENGTH_GLOBAL = 2;
44    public static final int STRENGTH_PERSISTABLE = 3;
45
46    final int userHandle;
47    final String sourcePkg;
48    final String targetPkg;
49
50    /** Cached UID of {@link #targetPkg}; should not be persisted */
51    final int targetUid;
52
53    final Uri uri;
54
55    /**
56     * Allowed modes. All permission enforcement should use this field. Must
57     * always be a combination of {@link #ownedModeFlags},
58     * {@link #globalModeFlags}, {@link #persistableModeFlags}, and
59     * {@link #persistedModeFlags}. Mutations <em>must</em> only be performed by
60     * the owning class.
61     */
62    int modeFlags = 0;
63
64    /** Allowed modes with explicit owner. */
65    int ownedModeFlags = 0;
66    /** Allowed modes without explicit owner. */
67    int globalModeFlags = 0;
68    /** Allowed modes that have been offered for possible persisting. */
69    int persistableModeFlags = 0;
70    /** Allowed modes that should be persisted across device boots. */
71    int persistedModeFlags = 0;
72
73    /**
74     * Timestamp when {@link #persistedModeFlags} was first defined in
75     * {@link System#currentTimeMillis()} time base.
76     */
77    long persistedCreateTime = INVALID_TIME;
78
79    private static final long INVALID_TIME = Long.MIN_VALUE;
80
81    private HashSet<UriPermissionOwner> mReadOwners;
82    private HashSet<UriPermissionOwner> mWriteOwners;
83
84    private String stringName;
85
86    UriPermission(String sourcePkg, String targetPkg, int targetUid, Uri uri) {
87        this.userHandle = UserHandle.getUserId(targetUid);
88        this.sourcePkg = sourcePkg;
89        this.targetPkg = targetPkg;
90        this.targetUid = targetUid;
91        this.uri = uri;
92    }
93
94    private void updateModeFlags() {
95        modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
96    }
97
98    /**
99     * Initialize persisted modes as read from file. This doesn't issue any
100     * global or owner grants.
101     */
102    void initPersistedModes(int modeFlags, long createdTime) {
103        persistableModeFlags = modeFlags;
104        persistedModeFlags = modeFlags;
105        persistedCreateTime = createdTime;
106
107        updateModeFlags();
108    }
109
110    void grantModes(int modeFlags, boolean persistable, UriPermissionOwner owner) {
111        if (persistable) {
112            persistableModeFlags |= modeFlags;
113        }
114
115        if (owner == null) {
116            globalModeFlags |= modeFlags;
117        } else {
118            if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
119                addReadOwner(owner);
120            }
121            if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
122                addWriteOwner(owner);
123            }
124        }
125
126        updateModeFlags();
127    }
128
129    /**
130     * @return if mode changes should trigger persisting.
131     */
132    boolean takePersistableModes(int modeFlags) {
133        if ((modeFlags & persistableModeFlags) != modeFlags) {
134            throw new SecurityException("Requested flags 0x"
135                    + Integer.toHexString(modeFlags) + ", but only 0x"
136                    + Integer.toHexString(persistableModeFlags) + " are allowed");
137        }
138
139        final int before = persistedModeFlags;
140        persistedModeFlags |= (persistableModeFlags & modeFlags);
141
142        if (persistedModeFlags != 0) {
143            persistedCreateTime = System.currentTimeMillis();
144        }
145
146        updateModeFlags();
147        return persistedModeFlags != before;
148    }
149
150    boolean releasePersistableModes(int modeFlags) {
151        final int before = persistedModeFlags;
152
153        persistableModeFlags &= ~modeFlags;
154        persistedModeFlags &= ~modeFlags;
155
156        if (persistedModeFlags == 0) {
157            persistedCreateTime = INVALID_TIME;
158        }
159
160        updateModeFlags();
161        return persistedModeFlags != before;
162    }
163
164    /**
165     * @return if mode changes should trigger persisting.
166     */
167    boolean clearModes(int modeFlags, boolean persistable) {
168        final int before = persistedModeFlags;
169
170        if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
171            if (persistable) {
172                persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
173                persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
174            }
175            globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
176            if (mReadOwners != null) {
177                ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
178                for (UriPermissionOwner r : mReadOwners) {
179                    r.removeReadPermission(this);
180                }
181                mReadOwners = null;
182            }
183        }
184        if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
185            if (persistable) {
186                persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
187                persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
188            }
189            globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
190            if (mWriteOwners != null) {
191                ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
192                for (UriPermissionOwner r : mWriteOwners) {
193                    r.removeWritePermission(this);
194                }
195                mWriteOwners = null;
196            }
197        }
198
199        if (persistedModeFlags == 0) {
200            persistedCreateTime = INVALID_TIME;
201        }
202
203        updateModeFlags();
204        return persistedModeFlags != before;
205    }
206
207    /**
208     * Return strength of this permission grant for the given flags.
209     */
210    public int getStrength(int modeFlags) {
211        if ((persistableModeFlags & modeFlags) == modeFlags) {
212            return STRENGTH_PERSISTABLE;
213        } else if ((globalModeFlags & modeFlags) == modeFlags) {
214            return STRENGTH_GLOBAL;
215        } else if ((ownedModeFlags & modeFlags) == modeFlags) {
216            return STRENGTH_OWNED;
217        } else {
218            return STRENGTH_NONE;
219        }
220    }
221
222    private void addReadOwner(UriPermissionOwner owner) {
223        if (mReadOwners == null) {
224            mReadOwners = Sets.newHashSet();
225            ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
226            updateModeFlags();
227        }
228        if (mReadOwners.add(owner)) {
229            owner.addReadPermission(this);
230        }
231    }
232
233    /**
234     * Remove given read owner, updating {@Link #modeFlags} as needed.
235     */
236    void removeReadOwner(UriPermissionOwner owner) {
237        if (!mReadOwners.remove(owner)) {
238            Log.wtf(TAG, "Unknown read owner " + owner + " in " + this);
239        }
240        if (mReadOwners.size() == 0) {
241            mReadOwners = null;
242            ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
243            updateModeFlags();
244        }
245    }
246
247    private void addWriteOwner(UriPermissionOwner owner) {
248        if (mWriteOwners == null) {
249            mWriteOwners = Sets.newHashSet();
250            ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
251            updateModeFlags();
252        }
253        if (mWriteOwners.add(owner)) {
254            owner.addWritePermission(this);
255        }
256    }
257
258    /**
259     * Remove given write owner, updating {@Link #modeFlags} as needed.
260     */
261    void removeWriteOwner(UriPermissionOwner owner) {
262        if (!mWriteOwners.remove(owner)) {
263            Log.wtf(TAG, "Unknown write owner " + owner + " in " + this);
264        }
265        if (mWriteOwners.size() == 0) {
266            mWriteOwners = null;
267            ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
268            updateModeFlags();
269        }
270    }
271
272    @Override
273    public String toString() {
274        if (stringName != null) {
275            return stringName;
276        }
277        StringBuilder sb = new StringBuilder(128);
278        sb.append("UriPermission{");
279        sb.append(Integer.toHexString(System.identityHashCode(this)));
280        sb.append(' ');
281        sb.append(uri);
282        sb.append('}');
283        return stringName = sb.toString();
284    }
285
286    void dump(PrintWriter pw, String prefix) {
287        pw.print(prefix);
288        pw.print("userHandle=" + userHandle);
289        pw.print(" sourcePkg=" + sourcePkg);
290        pw.println(" targetPkg=" + targetPkg);
291
292        pw.print(prefix);
293        pw.print("mode=0x" + Integer.toHexString(modeFlags));
294        pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
295        pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
296        pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
297        pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
298        if (persistedCreateTime != INVALID_TIME) {
299            pw.print(" persistedCreate=" + persistedCreateTime);
300        }
301        pw.println();
302
303        if (mReadOwners != null) {
304            pw.print(prefix);
305            pw.println("readOwners:");
306            for (UriPermissionOwner owner : mReadOwners) {
307                pw.print(prefix);
308                pw.println("  * " + owner);
309            }
310        }
311        if (mWriteOwners != null) {
312            pw.print(prefix);
313            pw.println("writeOwners:");
314            for (UriPermissionOwner owner : mReadOwners) {
315                pw.print(prefix);
316                pw.println("  * " + owner);
317            }
318        }
319    }
320
321    public static class PersistedTimeComparator implements Comparator<UriPermission> {
322        @Override
323        public int compare(UriPermission lhs, UriPermission rhs) {
324            return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
325        }
326    }
327
328    /**
329     * Snapshot of {@link UriPermission} with frozen
330     * {@link UriPermission#persistedModeFlags} state.
331     */
332    public static class Snapshot {
333        final int userHandle;
334        final String sourcePkg;
335        final String targetPkg;
336        final Uri uri;
337        final int persistedModeFlags;
338        final long persistedCreateTime;
339
340        private Snapshot(UriPermission perm) {
341            this.userHandle = perm.userHandle;
342            this.sourcePkg = perm.sourcePkg;
343            this.targetPkg = perm.targetPkg;
344            this.uri = perm.uri;
345            this.persistedModeFlags = perm.persistedModeFlags;
346            this.persistedCreateTime = perm.persistedCreateTime;
347        }
348    }
349
350    public Snapshot snapshot() {
351        return new Snapshot(this);
352    }
353
354    public android.content.UriPermission buildPersistedPublicApiObject() {
355        return new android.content.UriPermission(uri, persistedModeFlags, persistedCreateTime);
356    }
357}
358