1 /*
2  * Copyright (C) 2022 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.sdksandbox;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.os.Binder;
23 import android.os.IBinder;
24 import android.os.Process;
25 import android.os.UserHandle;
26 
27 import java.util.Objects;
28 
29 /**
30  * Representation of a caller for an SDK sandbox.
31  * @hide
32  */
33 public final class CallingInfo {
34 
35     private final int mUid;
36     private final String mPackageName;
37     private final @Nullable IBinder mAppProcessToken;
38     private boolean mIsCallFromSdkSandbox;
39 
enforceCallingPackageBelongsToUid( Context context, int uid, String packageName)40     private static void enforceCallingPackageBelongsToUid(
41             Context context, int uid, String packageName) {
42         int packageUid;
43         PackageManager pm =
44                 context.createContextAsUser(UserHandle.getUserHandleForUid(uid), 0)
45                         .getPackageManager();
46         try {
47             packageUid = pm.getPackageUid(packageName, 0);
48         } catch (PackageManager.NameNotFoundException e) {
49             throw new SecurityException(packageName + " not found");
50         }
51         if (packageUid != uid) {
52             throw new SecurityException(packageName + " does not belong to uid " + uid);
53         }
54     }
55 
CallingInfo(int uid, String packageName, @Nullable IBinder processTokenBinder)56     public CallingInfo(int uid, String packageName, @Nullable IBinder processTokenBinder) {
57         mUid = uid;
58         mPackageName = Objects.requireNonNull(packageName);
59         mAppProcessToken = processTokenBinder;
60         mIsCallFromSdkSandbox = Process.isSdkSandboxUid(mUid);
61     }
62 
CallingInfo(int uid, String packageName)63     public CallingInfo(int uid, String packageName) {
64         this(uid, packageName, null);
65     }
66 
fromExternal(Context context, int uid, String packageNameUnchecked)67     static CallingInfo fromExternal(Context context, int uid, String packageNameUnchecked) {
68         enforceCallingPackageBelongsToUid(context, uid, packageNameUnchecked);
69         CallingInfo callingInfo = new CallingInfo(uid, packageNameUnchecked);
70         callingInfo.mIsCallFromSdkSandbox = true;
71         return callingInfo;
72     }
73 
fromBinder(Context context, String packageNameUnchecked)74     static CallingInfo fromBinder(Context context, String packageNameUnchecked) {
75         return fromBinderWithApplicationThread(context, packageNameUnchecked, null);
76     }
77 
fromBinderWithApplicationThread( Context context, String packageNameUnchecked, @Nullable IBinder callingApplicationThread)78     static CallingInfo fromBinderWithApplicationThread(
79             Context context,
80             String packageNameUnchecked,
81             @Nullable IBinder callingApplicationThread) {
82         final int uid = Binder.getCallingUid();
83         enforceCallingPackageBelongsToUid(context, uid, packageNameUnchecked);
84 
85         return new CallingInfo(uid, packageNameUnchecked, callingApplicationThread);
86     }
87 
getUid()88     public int getUid() {
89         return mUid;
90     }
91 
getAppProcessToken()92     public @Nullable IBinder getAppProcessToken() {
93         return mAppProcessToken;
94     }
95 
getPackageName()96     public String getPackageName() {
97         return mPackageName;
98     }
99 
isCallFromSdkSandbox()100     public boolean isCallFromSdkSandbox() {
101         return mIsCallFromSdkSandbox;
102     }
103 
104     @Override
toString()105     public String toString() {
106         return "CallingInfo{"
107                 + "mUid="
108                 + mUid
109                 + ", mPackageName='"
110                 + mPackageName
111                 + ", mAppProcessToken='"
112                 + mAppProcessToken
113                 + "'}";
114     }
115 
116     @Override
equals(Object o)117     public boolean equals(Object o) {
118         // Note that mApplicationThread is not part of the comparison, because it is not always set,
119         // nor is it necessary to determine whether two instances refer to the same caller.
120         if (this == o) return true;
121         if (!(o instanceof CallingInfo)) return false;
122         CallingInfo that = (CallingInfo) o;
123         return mUid == that.mUid && mPackageName.equals(that.mPackageName);
124     }
125 
126     @Override
hashCode()127     public int hashCode() {
128         return mUid ^ mPackageName.hashCode();
129     }
130 }
131