• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 android.location.util.identity;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.os.Binder;
22 import android.os.Process;
23 import android.os.UserHandle;
24 import android.os.WorkSource;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 import com.android.internal.util.ArrayUtils;
28 import com.android.internal.util.HexDump;
29 
30 import java.util.Objects;
31 
32 /**
33  * Identifying information on a caller.
34  *
35  * @hide
36  */
37 public final class CallerIdentity {
38 
39     /**
40      * Construct a CallerIdentity for test purposes.
41      */
42     @VisibleForTesting
forTest(int uid, int pid, String packageName, @Nullable String attributionTag)43     public static CallerIdentity forTest(int uid, int pid, String packageName,
44             @Nullable String attributionTag) {
45         return forTest(uid, pid, packageName, attributionTag, null);
46     }
47 
48     /**
49      * Construct a CallerIdentity for test purposes.
50      */
51     @VisibleForTesting
forTest(int uid, int pid, String packageName, @Nullable String attributionTag, @Nullable String listenerId)52     public static CallerIdentity forTest(int uid, int pid, String packageName,
53             @Nullable String attributionTag, @Nullable String listenerId) {
54         return new CallerIdentity(uid, pid, packageName, attributionTag, listenerId);
55     }
56 
57     /**
58      * Returns a CallerIdentity with PID and listener ID information stripped. This is mostly
59      * useful for aggregating information for debug purposes, and should not be used in any API with
60      * security requirements.
61      */
forAggregation(CallerIdentity callerIdentity)62     public static CallerIdentity forAggregation(CallerIdentity callerIdentity) {
63         if (callerIdentity.getPid() == 0 && callerIdentity.getListenerId() == null) {
64             return callerIdentity;
65         }
66 
67         return new CallerIdentity(callerIdentity.getUid(), 0, callerIdentity.getPackageName(),
68                 callerIdentity.getAttributionTag(), null);
69     }
70 
71     /**
72      * Creates a CallerIdentity for the current process and context.
73      */
fromContext(Context context)74     public static CallerIdentity fromContext(Context context) {
75         return new CallerIdentity(Process.myUid(), Process.myPid(), context.getPackageName(),
76                 context.getAttributionTag(), null);
77     }
78 
79     /**
80      * Creates a CallerIdentity from the current binder identity, using the given package and
81      * feature id. The package will be checked to enforce it belongs to the calling uid, and a
82      * security exception will be thrown if it is invalid.
83      */
fromBinder(Context context, String packageName, @Nullable String attributionTag)84     public static CallerIdentity fromBinder(Context context, String packageName,
85             @Nullable String attributionTag) {
86         return fromBinder(context, packageName, attributionTag, null);
87     }
88 
89     /**
90      * Creates a CallerIdentity from the current binder identity, using the given package, feature
91      * id, and listener id. The package will be checked to enforce it belongs to the calling uid,
92      * and a security exception will be thrown if it is invalid.
93      */
fromBinder(Context context, String packageName, @Nullable String attributionTag, @Nullable String listenerId)94     public static CallerIdentity fromBinder(Context context, String packageName,
95             @Nullable String attributionTag, @Nullable String listenerId) {
96         int uid = Binder.getCallingUid();
97         if (!ArrayUtils.contains(context.getPackageManager().getPackagesForUid(uid), packageName)) {
98             throw new SecurityException("invalid package \"" + packageName + "\" for uid " + uid);
99         }
100 
101         return fromBinderUnsafe(packageName, attributionTag, listenerId);
102     }
103 
104     /**
105      * Creates a CallerIdentity from the current binder identity, using the given package and
106      * feature id. The package will not be checked to enforce that it belongs to the calling uid -
107      * this method should only be used if the package will be validated by some other means, such as
108      * an appops call.
109      */
fromBinderUnsafe(String packageName, @Nullable String attributionTag)110     public static CallerIdentity fromBinderUnsafe(String packageName,
111             @Nullable String attributionTag) {
112         return fromBinderUnsafe(packageName, attributionTag, null);
113     }
114 
115     /**
116      * Creates a CallerIdentity from the current binder identity, using the given package, feature
117      * id, and listener id. The package will not be checked to enforce that it belongs to the
118      * calling uid - this method should only be used if the package will be validated by some other
119      * means, such as an appops call.
120      */
fromBinderUnsafe(String packageName, @Nullable String attributionTag, @Nullable String listenerId)121     public static CallerIdentity fromBinderUnsafe(String packageName,
122             @Nullable String attributionTag, @Nullable String listenerId) {
123         return new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(),
124                 packageName, attributionTag, listenerId);
125     }
126 
127     private final int mUid;
128 
129     private final int mPid;
130 
131     private final String mPackageName;
132 
133     private final @Nullable String mAttributionTag;
134 
135     private final @Nullable String mListenerId;
136 
CallerIdentity(int uid, int pid, String packageName, @Nullable String attributionTag, @Nullable String listenerId)137     private CallerIdentity(int uid, int pid, String packageName,
138             @Nullable String attributionTag, @Nullable String listenerId) {
139         this.mUid = uid;
140         this.mPid = pid;
141         this.mPackageName = Objects.requireNonNull(packageName);
142         this.mAttributionTag = attributionTag;
143         this.mListenerId = listenerId;
144     }
145 
146     /** The calling UID. */
getUid()147     public int getUid() {
148         return mUid;
149     }
150 
151     /** The calling PID. */
getPid()152     public int getPid() {
153         return mPid;
154     }
155 
156     /** The calling user. */
getUserId()157     public int getUserId() {
158         return UserHandle.getUserId(mUid);
159     }
160 
161     /** The calling package name. */
getPackageName()162     public String getPackageName() {
163         return mPackageName;
164     }
165 
166     /** The calling attribution tag. */
getAttributionTag()167     public String getAttributionTag() {
168         return mAttributionTag;
169     }
170 
171     /**
172      * The calling listener id. A null listener id will match any other listener id for the purposes
173      * of {@link #equals(Object)}.
174      */
getListenerId()175     public String getListenerId() {
176         return mListenerId;
177     }
178 
179     /** Returns true if this represents a system server identity. */
isSystemServer()180     public boolean isSystemServer() {
181         return mUid == Process.SYSTEM_UID;
182     }
183 
184     /**
185      * Adds this identity to the worksource supplied, or if not worksource is supplied, creates a
186      * new worksource representing this identity.
187      */
addToWorkSource(@ullable WorkSource workSource)188     public WorkSource addToWorkSource(@Nullable WorkSource workSource) {
189         if (workSource == null) {
190             return new WorkSource(mUid, mPackageName);
191         } else {
192             workSource.add(mUid, mPackageName);
193             return workSource;
194         }
195     }
196 
197     @Override
toString()198     public String toString() {
199         int length = 10 + mPackageName.length();
200         if (mAttributionTag != null) {
201             length += mAttributionTag.length();
202         }
203 
204         StringBuilder builder = new StringBuilder(length);
205         builder.append(mUid).append("/").append(mPackageName);
206         if (mAttributionTag != null) {
207             builder.append("[");
208             if (mAttributionTag.startsWith(mPackageName)) {
209                 builder.append(mAttributionTag.substring(mPackageName.length()));
210             } else {
211                 builder.append(mAttributionTag);
212             }
213             builder.append("]");
214         }
215         if (mListenerId != null) {
216             builder.append("/").append(HexDump.toHexString(mListenerId.hashCode()));
217         }
218         return builder.toString();
219     }
220 
221     @Override
equals(Object o)222     public boolean equals(Object o) {
223         if (this == o) {
224             return true;
225         }
226         if (!(o instanceof CallerIdentity)) {
227             return false;
228         }
229         CallerIdentity that = (CallerIdentity) o;
230         return mUid == that.mUid
231                 && mPid == that.mPid
232                 && mPackageName.equals(that.mPackageName)
233                 && Objects.equals(mAttributionTag, that.mAttributionTag)
234                 && (mListenerId == null || that.mListenerId == null || mListenerId.equals(
235                 that.mListenerId));
236     }
237 
238     @Override
hashCode()239     public int hashCode() {
240         return Objects.hash(mUid, mPid, mPackageName, mAttributionTag);
241     }
242 }
243