Home | History | Annotate | Download | only in am
      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 
     17 package com.android.server.am;
     18 
     19 import android.content.Intent;
     20 import android.net.Uri;
     21 import android.os.UserHandle;
     22 import android.util.Log;
     23 
     24 import com.google.android.collect.Sets;
     25 
     26 import java.io.PrintWriter;
     27 import java.util.Comparator;
     28 import 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  */
     38 final 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