268 lines
9.2 KiB
Java
268 lines
9.2 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2020 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.location.util.identity;
|
||
|
|
||
|
import android.annotation.Nullable;
|
||
|
import android.content.Context;
|
||
|
import android.os.Binder;
|
||
|
import android.os.Process;
|
||
|
import android.os.UserHandle;
|
||
|
import android.os.WorkSource;
|
||
|
|
||
|
import com.android.internal.annotations.VisibleForTesting;
|
||
|
import com.android.internal.util.ArrayUtils;
|
||
|
import com.android.internal.util.HexDump;
|
||
|
|
||
|
import java.util.Objects;
|
||
|
|
||
|
/**
|
||
|
* Identifying information on a caller.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public final class CallerIdentity {
|
||
|
|
||
|
/**
|
||
|
* Construct a CallerIdentity for test purposes.
|
||
|
*/
|
||
|
@VisibleForTesting
|
||
|
public static CallerIdentity forTest(int uid, int pid, String packageName,
|
||
|
@Nullable String attributionTag) {
|
||
|
return forTest(uid, pid, packageName, attributionTag, null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construct a CallerIdentity for test purposes.
|
||
|
*/
|
||
|
@VisibleForTesting
|
||
|
public static CallerIdentity forTest(int uid, int pid, String packageName,
|
||
|
@Nullable String attributionTag, @Nullable String listenerId) {
|
||
|
return new CallerIdentity(uid, pid, packageName, attributionTag, listenerId);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a CallerIdentity with PID and listener ID information stripped. This is mostly
|
||
|
* useful for aggregating information for debug purposes, and should not be used in any API with
|
||
|
* security requirements.
|
||
|
*/
|
||
|
public static CallerIdentity forAggregation(CallerIdentity callerIdentity) {
|
||
|
if (callerIdentity.getPid() == 0 && callerIdentity.getListenerId() == null) {
|
||
|
return callerIdentity;
|
||
|
}
|
||
|
|
||
|
return new CallerIdentity(callerIdentity.getUid(), 0, callerIdentity.getPackageName(),
|
||
|
callerIdentity.getAttributionTag(), null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a CallerIdentity for the current process and context.
|
||
|
*/
|
||
|
public static CallerIdentity fromContext(Context context) {
|
||
|
return new CallerIdentity(Process.myUid(), Process.myPid(), context.getPackageName(),
|
||
|
context.getAttributionTag(), null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a CallerIdentity from the current binder identity, using the given package and
|
||
|
* feature id. The package will be checked to enforce it belongs to the calling uid, and a
|
||
|
* security exception will be thrown if it is invalid.
|
||
|
*/
|
||
|
public static CallerIdentity fromBinder(Context context, String packageName,
|
||
|
@Nullable String attributionTag) {
|
||
|
return fromBinder(context, packageName, attributionTag, null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a CallerIdentity from the current binder identity, using the given package, feature
|
||
|
* id, and listener id. The package will be checked to enforce it belongs to the calling uid,
|
||
|
* and a security exception will be thrown if it is invalid.
|
||
|
*/
|
||
|
public static CallerIdentity fromBinder(Context context, String packageName,
|
||
|
@Nullable String attributionTag, @Nullable String listenerId) {
|
||
|
int uid = Binder.getCallingUid();
|
||
|
if (!ArrayUtils.contains(context.getPackageManager().getPackagesForUid(uid), packageName)) {
|
||
|
throw new SecurityException("invalid package \"" + packageName + "\" for uid " + uid);
|
||
|
}
|
||
|
|
||
|
return fromBinderUnsafe(packageName, attributionTag, listenerId);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a CallerIdentity from the current binder identity, using the given package and
|
||
|
* feature id. The package will not be checked to enforce that it belongs to the calling uid -
|
||
|
* this method should only be used if the package will be validated by some other means, such as
|
||
|
* an appops call.
|
||
|
*/
|
||
|
public static CallerIdentity fromBinderUnsafe(String packageName,
|
||
|
@Nullable String attributionTag) {
|
||
|
return fromBinderUnsafe(packageName, attributionTag, null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a CallerIdentity from the current binder identity, using the given package, feature
|
||
|
* id, and listener id. The package will not be checked to enforce that it belongs to the
|
||
|
* calling uid - this method should only be used if the package will be validated by some other
|
||
|
* means, such as an appops call.
|
||
|
*/
|
||
|
public static CallerIdentity fromBinderUnsafe(String packageName,
|
||
|
@Nullable String attributionTag, @Nullable String listenerId) {
|
||
|
return new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(),
|
||
|
packageName, attributionTag, listenerId);
|
||
|
}
|
||
|
|
||
|
// in some tests these constants are loaded too early leading to an "incorrect" view of the
|
||
|
// current pid and uid. load lazily to prevent this problem in tests.
|
||
|
private static class Loader {
|
||
|
private static final int MY_UID = Process.myUid();
|
||
|
private static final int MY_PID = Process.myPid();
|
||
|
}
|
||
|
|
||
|
private final int mUid;
|
||
|
|
||
|
private final int mPid;
|
||
|
|
||
|
private final String mPackageName;
|
||
|
|
||
|
@Nullable private final String mAttributionTag;
|
||
|
|
||
|
@Nullable private final String mListenerId;
|
||
|
|
||
|
private CallerIdentity(int uid, int pid, String packageName,
|
||
|
@Nullable String attributionTag, @Nullable String listenerId) {
|
||
|
this.mUid = uid;
|
||
|
this.mPid = pid;
|
||
|
this.mPackageName = Objects.requireNonNull(packageName);
|
||
|
this.mAttributionTag = attributionTag;
|
||
|
this.mListenerId = listenerId;
|
||
|
}
|
||
|
|
||
|
/** The calling UID. */
|
||
|
public int getUid() {
|
||
|
return mUid;
|
||
|
}
|
||
|
|
||
|
/** The calling PID. */
|
||
|
public int getPid() {
|
||
|
return mPid;
|
||
|
}
|
||
|
|
||
|
/** The calling user. */
|
||
|
public int getUserId() {
|
||
|
return UserHandle.getUserId(mUid);
|
||
|
}
|
||
|
|
||
|
/** The calling package name. */
|
||
|
public String getPackageName() {
|
||
|
return mPackageName;
|
||
|
}
|
||
|
|
||
|
/** The calling attribution tag. */
|
||
|
public String getAttributionTag() {
|
||
|
return mAttributionTag;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The calling listener id. A null listener id will match any other listener id for the purposes
|
||
|
* of {@link #equals(Object)}.
|
||
|
*/
|
||
|
public String getListenerId() {
|
||
|
return mListenerId;
|
||
|
}
|
||
|
|
||
|
/** Returns true if this represents a system server identity. */
|
||
|
public boolean isSystemServer() {
|
||
|
return mUid == Process.SYSTEM_UID;
|
||
|
}
|
||
|
|
||
|
/** Returns true if this identity represents the same user this code is running in. */
|
||
|
public boolean isMyUser() {
|
||
|
return UserHandle.getUserId(mUid) == UserHandle.getUserId(Loader.MY_UID);
|
||
|
}
|
||
|
|
||
|
/** Returns true if this identity represents the same uid this code is running in. */
|
||
|
public boolean isMyUid() {
|
||
|
return mUid == Loader.MY_UID;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if this identity represents the same process this code is running in. Returns
|
||
|
* false if the identity process is unknown.
|
||
|
*/
|
||
|
public boolean isMyProcess() {
|
||
|
return mPid == Loader.MY_PID;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds this identity to the worksource supplied, or if not worksource is supplied, creates a
|
||
|
* new worksource representing this identity.
|
||
|
*/
|
||
|
public WorkSource addToWorkSource(@Nullable WorkSource workSource) {
|
||
|
if (workSource == null) {
|
||
|
return new WorkSource(mUid, mPackageName);
|
||
|
} else {
|
||
|
workSource.add(mUid, mPackageName);
|
||
|
return workSource;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
int length = 10 + mPackageName.length();
|
||
|
if (mAttributionTag != null) {
|
||
|
length += mAttributionTag.length();
|
||
|
}
|
||
|
|
||
|
StringBuilder builder = new StringBuilder(length);
|
||
|
builder.append(mUid).append("/").append(mPackageName);
|
||
|
if (mAttributionTag != null) {
|
||
|
builder.append("[");
|
||
|
if (mAttributionTag.startsWith(mPackageName)) {
|
||
|
builder.append(mAttributionTag.substring(mPackageName.length()));
|
||
|
} else {
|
||
|
builder.append(mAttributionTag);
|
||
|
}
|
||
|
builder.append("]");
|
||
|
}
|
||
|
if (mListenerId != null) {
|
||
|
builder.append("/").append(HexDump.toHexString(mListenerId.hashCode()));
|
||
|
}
|
||
|
return builder.toString();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean equals(Object o) {
|
||
|
if (this == o) {
|
||
|
return true;
|
||
|
}
|
||
|
if (!(o instanceof CallerIdentity)) {
|
||
|
return false;
|
||
|
}
|
||
|
CallerIdentity that = (CallerIdentity) o;
|
||
|
return mUid == that.mUid
|
||
|
&& mPid == that.mPid
|
||
|
&& mPackageName.equals(that.mPackageName)
|
||
|
&& Objects.equals(mAttributionTag, that.mAttributionTag)
|
||
|
&& (mListenerId == null || that.mListenerId == null || mListenerId.equals(
|
||
|
that.mListenerId));
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int hashCode() {
|
||
|
return Objects.hash(mUid, mPid, mPackageName, mAttributionTag);
|
||
|
}
|
||
|
}
|