1/*
2 * Copyright (C) 2017 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.job;
18
19import android.app.IActivityManager;
20import android.content.ClipData;
21import android.content.ContentProvider;
22import android.content.Intent;
23import android.net.Uri;
24import android.os.IBinder;
25import android.os.RemoteException;
26import android.os.UserHandle;
27import android.util.Slog;
28
29import java.io.PrintWriter;
30import java.util.ArrayList;
31
32public final class GrantedUriPermissions {
33    private final int mGrantFlags;
34    private final int mSourceUserId;
35    private final String mTag;
36    private final IBinder mPermissionOwner;
37    private final ArrayList<Uri> mUris = new ArrayList<>();
38
39    private GrantedUriPermissions(IActivityManager am, int grantFlags, int uid, String tag)
40            throws RemoteException {
41        mGrantFlags = grantFlags;
42        mSourceUserId = UserHandle.getUserId(uid);
43        mTag = tag;
44        mPermissionOwner = am.newUriPermissionOwner("job: " + tag);
45    }
46
47    public void revoke(IActivityManager am) {
48        for (int i = mUris.size()-1; i >= 0; i--) {
49            try {
50                am.revokeUriPermissionFromOwner(mPermissionOwner, mUris.get(i),
51                        mGrantFlags, mSourceUserId);
52            } catch (RemoteException e) {
53            }
54        }
55        mUris.clear();
56    }
57
58    public static boolean checkGrantFlags(int grantFlags) {
59        return (grantFlags & (Intent.FLAG_GRANT_WRITE_URI_PERMISSION
60                |Intent.FLAG_GRANT_READ_URI_PERMISSION)) != 0;
61    }
62
63    public static GrantedUriPermissions createFromIntent(IActivityManager am, Intent intent,
64            int sourceUid, String targetPackage, int targetUserId, String tag) {
65        int grantFlags = intent.getFlags();
66        if (!checkGrantFlags(grantFlags)) {
67            return null;
68        }
69
70        GrantedUriPermissions perms = null;
71
72        Uri data = intent.getData();
73        if (data != null) {
74            perms = grantUri(am, data, sourceUid, targetPackage, targetUserId, grantFlags, tag,
75                    perms);
76        }
77
78        ClipData clip = intent.getClipData();
79        if (clip != null) {
80            perms = grantClip(am, clip, sourceUid, targetPackage, targetUserId, grantFlags, tag,
81                    perms);
82        }
83
84        return perms;
85    }
86
87    public static GrantedUriPermissions createFromClip(IActivityManager am, ClipData clip,
88            int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag) {
89        if (!checkGrantFlags(grantFlags)) {
90            return null;
91        }
92        GrantedUriPermissions perms = null;
93        if (clip != null) {
94            perms = grantClip(am, clip, sourceUid, targetPackage, targetUserId, grantFlags,
95                    tag, perms);
96        }
97        return perms;
98    }
99
100    private static GrantedUriPermissions grantClip(IActivityManager am, ClipData clip,
101            int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag,
102            GrantedUriPermissions curPerms) {
103        final int N = clip.getItemCount();
104        for (int i = 0; i < N; i++) {
105            curPerms = grantItem(am, clip.getItemAt(i), sourceUid, targetPackage, targetUserId,
106                    grantFlags, tag, curPerms);
107        }
108        return curPerms;
109    }
110
111    private static GrantedUriPermissions grantUri(IActivityManager am, Uri uri,
112            int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag,
113            GrantedUriPermissions curPerms) {
114        try {
115            int sourceUserId = ContentProvider.getUserIdFromUri(uri,
116                    UserHandle.getUserId(sourceUid));
117            uri = ContentProvider.getUriWithoutUserId(uri);
118            if (curPerms == null) {
119                curPerms = new GrantedUriPermissions(am, grantFlags, sourceUid, tag);
120            }
121            am.grantUriPermissionFromOwner(curPerms.mPermissionOwner, sourceUid, targetPackage,
122                    uri, grantFlags, sourceUserId, targetUserId);
123            curPerms.mUris.add(uri);
124        } catch (RemoteException e) {
125            Slog.e("JobScheduler", "AM dead");
126        }
127        return curPerms;
128    }
129
130    private static GrantedUriPermissions grantItem(IActivityManager am, ClipData.Item item,
131            int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag,
132            GrantedUriPermissions curPerms) {
133        if (item.getUri() != null) {
134            curPerms = grantUri(am, item.getUri(), sourceUid, targetPackage, targetUserId,
135                    grantFlags, tag, curPerms);
136        }
137        Intent intent = item.getIntent();
138        if (intent != null && intent.getData() != null) {
139            curPerms = grantUri(am, intent.getData(), sourceUid, targetPackage, targetUserId,
140                    grantFlags, tag, curPerms);
141        }
142        return curPerms;
143    }
144
145    // Dumpsys infrastructure
146    public void dump(PrintWriter pw, String prefix) {
147        pw.print(prefix); pw.print("mGrantFlags=0x"); pw.print(Integer.toHexString(mGrantFlags));
148        pw.print(" mSourceUserId="); pw.println(mSourceUserId);
149        pw.print(prefix); pw.print("mTag="); pw.println(mTag);
150        pw.print(prefix); pw.print("mPermissionOwner="); pw.println(mPermissionOwner);
151        for (int i = 0; i < mUris.size(); i++) {
152            pw.print(prefix); pw.print("#"); pw.print(i); pw.print(": ");
153            pw.println(mUris.get(i));
154        }
155    }
156}
157