268 lines
9.5 KiB
Java
268 lines
9.5 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2018 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.telephony.euicc;
|
||
|
|
||
|
import android.annotation.IntDef;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.annotation.SystemApi;
|
||
|
import android.os.Parcel;
|
||
|
import android.os.Parcelable;
|
||
|
import android.service.carrier.CarrierIdentifier;
|
||
|
import android.service.euicc.EuiccProfileInfo;
|
||
|
import android.text.TextUtils;
|
||
|
|
||
|
import com.android.internal.annotations.VisibleForTesting;
|
||
|
|
||
|
import java.lang.annotation.Retention;
|
||
|
import java.lang.annotation.RetentionPolicy;
|
||
|
import java.util.Arrays;
|
||
|
import java.util.List;
|
||
|
|
||
|
/**
|
||
|
* This represents the RAT (Rules Authorisation Table) stored on eUICC.
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi
|
||
|
public final class EuiccRulesAuthTable implements Parcelable {
|
||
|
/**
|
||
|
* Profile policy rule flags
|
||
|
*
|
||
|
* @removed mistakenly exposed previously
|
||
|
*/
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
@IntDef(flag = true, prefix = { "POLICY_RULE_FLAG_" }, value = {
|
||
|
POLICY_RULE_FLAG_CONSENT_REQUIRED
|
||
|
})
|
||
|
public @interface PolicyRuleFlag {}
|
||
|
|
||
|
/** User consent is required to install the profile. */
|
||
|
public static final int POLICY_RULE_FLAG_CONSENT_REQUIRED = 1;
|
||
|
|
||
|
private final int[] mPolicyRules;
|
||
|
private final CarrierIdentifier[][] mCarrierIds;
|
||
|
private final int[] mPolicyRuleFlags;
|
||
|
|
||
|
/** This is used to build new {@link EuiccRulesAuthTable} instance. */
|
||
|
public static final class Builder {
|
||
|
private int[] mPolicyRules;
|
||
|
private CarrierIdentifier[][] mCarrierIds;
|
||
|
private int[] mPolicyRuleFlags;
|
||
|
private int mPosition;
|
||
|
|
||
|
/**
|
||
|
* Creates a new builder.
|
||
|
*
|
||
|
* @param ruleNum The number of authorisation rules in the table.
|
||
|
*/
|
||
|
public Builder(int ruleNum) {
|
||
|
mPolicyRules = new int[ruleNum];
|
||
|
mCarrierIds = new CarrierIdentifier[ruleNum][];
|
||
|
mPolicyRuleFlags = new int[ruleNum];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Builds the RAT instance. This builder should not be used anymore after this method is
|
||
|
* called, otherwise {@link NullPointerException} will be thrown.
|
||
|
*/
|
||
|
public EuiccRulesAuthTable build() {
|
||
|
if (mPosition != mPolicyRules.length) {
|
||
|
throw new IllegalStateException(
|
||
|
"Not enough rules are added, expected: "
|
||
|
+ mPolicyRules.length
|
||
|
+ ", added: "
|
||
|
+ mPosition);
|
||
|
}
|
||
|
return new EuiccRulesAuthTable(mPolicyRules, mCarrierIds, mPolicyRuleFlags);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds an authorisation rule.
|
||
|
*
|
||
|
* @throws ArrayIndexOutOfBoundsException If the {@code mPosition} is larger than the size
|
||
|
* this table.
|
||
|
*/
|
||
|
public Builder add(int policyRules, List<CarrierIdentifier> carrierId, int policyRuleFlags) {
|
||
|
if (mPosition >= mPolicyRules.length) {
|
||
|
throw new ArrayIndexOutOfBoundsException(mPosition);
|
||
|
}
|
||
|
mPolicyRules[mPosition] = policyRules;
|
||
|
if (carrierId != null && carrierId.size() > 0) {
|
||
|
mCarrierIds[mPosition] = carrierId.toArray(new CarrierIdentifier[carrierId.size()]);
|
||
|
}
|
||
|
mPolicyRuleFlags[mPosition] = policyRuleFlags;
|
||
|
mPosition++;
|
||
|
return this;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param mccRule A 2-character or 3-character string which can be either MCC or MNC. The
|
||
|
* character 'E' is used as a wild char to match any digit.
|
||
|
* @param mcc A 2-character or 3-character string which can be either MCC or MNC.
|
||
|
* @return Whether the {@code mccRule} matches {@code mcc}.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@VisibleForTesting
|
||
|
public static boolean match(String mccRule, String mcc) {
|
||
|
if (mccRule.length() < mcc.length()) {
|
||
|
return false;
|
||
|
}
|
||
|
for (int i = 0; i < mccRule.length(); i++) {
|
||
|
// 'E' is the wild char to match any digit.
|
||
|
if (mccRule.charAt(i) == 'E'
|
||
|
|| (i < mcc.length() && mccRule.charAt(i) == mcc.charAt(i))) {
|
||
|
continue;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private EuiccRulesAuthTable(int[] policyRules, CarrierIdentifier[][] carrierIds,
|
||
|
int[] policyRuleFlags) {
|
||
|
mPolicyRules = policyRules;
|
||
|
mCarrierIds = carrierIds;
|
||
|
mPolicyRuleFlags = policyRuleFlags;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Finds the index of the first authorisation rule matching the given policy and carrier id. If
|
||
|
* the returned index is not negative, the carrier is allowed to apply this policy to its
|
||
|
* profile.
|
||
|
*
|
||
|
* @param policy The policy rule.
|
||
|
* @param carrierId The carrier id.
|
||
|
* @return The index of authorization rule. If no rule is found, -1 will be returned.
|
||
|
*/
|
||
|
public int findIndex(@EuiccProfileInfo.PolicyRule int policy, CarrierIdentifier carrierId) {
|
||
|
for (int i = 0; i < mPolicyRules.length; i++) {
|
||
|
if ((mPolicyRules[i] & policy) == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
CarrierIdentifier[] carrierIds = mCarrierIds[i];
|
||
|
if (carrierIds == null || carrierIds.length == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
for (int j = 0; j < carrierIds.length; j++) {
|
||
|
CarrierIdentifier ruleCarrierId = carrierIds[j];
|
||
|
if (!match(ruleCarrierId.getMcc(), carrierId.getMcc())
|
||
|
|| !match(ruleCarrierId.getMnc(), carrierId.getMnc())) {
|
||
|
continue;
|
||
|
}
|
||
|
String gid = ruleCarrierId.getGid1();
|
||
|
if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid1())) {
|
||
|
continue;
|
||
|
}
|
||
|
gid = ruleCarrierId.getGid2();
|
||
|
if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid2())) {
|
||
|
continue;
|
||
|
}
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Tests if the entry in the table has the given policy rule flag.
|
||
|
*
|
||
|
* @param index The index of the entry.
|
||
|
* @param flag The policy rule flag to be tested.
|
||
|
* @throws ArrayIndexOutOfBoundsException If the {@code index} is negative or larger than the
|
||
|
* size of this table.
|
||
|
*/
|
||
|
public boolean hasPolicyRuleFlag(int index, @PolicyRuleFlag int flag) {
|
||
|
if (index < 0 || index >= mPolicyRules.length) {
|
||
|
throw new ArrayIndexOutOfBoundsException(index);
|
||
|
}
|
||
|
return (mPolicyRuleFlags[index] & flag) != 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int describeContents() {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void writeToParcel(Parcel dest, int flags) {
|
||
|
dest.writeIntArray(mPolicyRules);
|
||
|
for (CarrierIdentifier[] ids : mCarrierIds) {
|
||
|
dest.writeTypedArray(ids, flags);
|
||
|
}
|
||
|
dest.writeIntArray(mPolicyRuleFlags);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean equals(@Nullable Object obj) {
|
||
|
if (this == obj) {
|
||
|
return true;
|
||
|
}
|
||
|
if (obj == null || getClass() != obj.getClass()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
EuiccRulesAuthTable that = (EuiccRulesAuthTable) obj;
|
||
|
if (mCarrierIds.length != that.mCarrierIds.length) {
|
||
|
return false;
|
||
|
}
|
||
|
for (int i = 0; i < mCarrierIds.length; i++) {
|
||
|
CarrierIdentifier[] carrierIds = mCarrierIds[i];
|
||
|
CarrierIdentifier[] thatCarrierIds = that.mCarrierIds[i];
|
||
|
if (carrierIds != null && thatCarrierIds != null) {
|
||
|
if (carrierIds.length != thatCarrierIds.length) {
|
||
|
return false;
|
||
|
}
|
||
|
for (int j = 0; j < carrierIds.length; j++) {
|
||
|
if (!carrierIds[j].equals(thatCarrierIds[j])) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
continue;
|
||
|
} else if (carrierIds == null && thatCarrierIds == null) {
|
||
|
continue;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return Arrays.equals(mPolicyRules, that.mPolicyRules)
|
||
|
&& Arrays.equals(mPolicyRuleFlags, that.mPolicyRuleFlags);
|
||
|
}
|
||
|
|
||
|
private EuiccRulesAuthTable(Parcel source) {
|
||
|
mPolicyRules = source.createIntArray();
|
||
|
int len = mPolicyRules.length;
|
||
|
mCarrierIds = new CarrierIdentifier[len][];
|
||
|
for (int i = 0; i < len; i++) {
|
||
|
mCarrierIds[i] = source.createTypedArray(CarrierIdentifier.CREATOR);
|
||
|
}
|
||
|
mPolicyRuleFlags = source.createIntArray();
|
||
|
}
|
||
|
|
||
|
public static final @android.annotation.NonNull Creator<EuiccRulesAuthTable> CREATOR =
|
||
|
new Creator<EuiccRulesAuthTable>() {
|
||
|
@Override
|
||
|
public EuiccRulesAuthTable createFromParcel(Parcel source) {
|
||
|
return new EuiccRulesAuthTable(source);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public EuiccRulesAuthTable[] newArray(int size) {
|
||
|
return new EuiccRulesAuthTable[size];
|
||
|
}
|
||
|
};
|
||
|
}
|