1 /* 2 * Copyright (C) 2018 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 package android.telephony.euicc; 17 18 import android.annotation.IntDef; 19 import android.annotation.Nullable; 20 import android.annotation.SystemApi; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.service.carrier.CarrierIdentifier; 24 import android.service.euicc.EuiccProfileInfo; 25 import android.text.TextUtils; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 29 import java.lang.annotation.Retention; 30 import java.lang.annotation.RetentionPolicy; 31 import java.util.Arrays; 32 import java.util.List; 33 34 /** 35 * This represents the RAT (Rules Authorisation Table) stored on eUICC. 36 * @hide 37 */ 38 @SystemApi 39 public final class EuiccRulesAuthTable implements Parcelable { 40 /** Profile policy rule flags */ 41 @Retention(RetentionPolicy.SOURCE) 42 @IntDef(flag = true, prefix = { "POLICY_RULE_FLAG_" }, value = { 43 POLICY_RULE_FLAG_CONSENT_REQUIRED 44 }) 45 /** @hide */ 46 public @interface PolicyRuleFlag {} 47 48 /** User consent is required to install the profile. */ 49 public static final int POLICY_RULE_FLAG_CONSENT_REQUIRED = 1; 50 51 private final int[] mPolicyRules; 52 private final CarrierIdentifier[][] mCarrierIds; 53 private final int[] mPolicyRuleFlags; 54 55 /** This is used to build new {@link EuiccRulesAuthTable} instance. */ 56 public static final class Builder { 57 private int[] mPolicyRules; 58 private CarrierIdentifier[][] mCarrierIds; 59 private int[] mPolicyRuleFlags; 60 private int mPosition; 61 62 /** 63 * Creates a new builder. 64 * 65 * @param ruleNum The number of authorisation rules in the table. 66 */ Builder(int ruleNum)67 public Builder(int ruleNum) { 68 mPolicyRules = new int[ruleNum]; 69 mCarrierIds = new CarrierIdentifier[ruleNum][]; 70 mPolicyRuleFlags = new int[ruleNum]; 71 } 72 73 /** 74 * Builds the RAT instance. This builder should not be used anymore after this method is 75 * called, otherwise {@link NullPointerException} will be thrown. 76 */ build()77 public EuiccRulesAuthTable build() { 78 if (mPosition != mPolicyRules.length) { 79 throw new IllegalStateException( 80 "Not enough rules are added, expected: " 81 + mPolicyRules.length 82 + ", added: " 83 + mPosition); 84 } 85 return new EuiccRulesAuthTable(mPolicyRules, mCarrierIds, mPolicyRuleFlags); 86 } 87 88 /** 89 * Adds an authorisation rule. 90 * 91 * @throws ArrayIndexOutOfBoundsException If the {@code mPosition} is larger than the size 92 * this table. 93 */ add(int policyRules, List<CarrierIdentifier> carrierId, int policyRuleFlags)94 public Builder add(int policyRules, List<CarrierIdentifier> carrierId, int policyRuleFlags) { 95 if (mPosition >= mPolicyRules.length) { 96 throw new ArrayIndexOutOfBoundsException(mPosition); 97 } 98 mPolicyRules[mPosition] = policyRules; 99 if (carrierId != null && carrierId.size() > 0) { 100 mCarrierIds[mPosition] = carrierId.toArray(new CarrierIdentifier[carrierId.size()]); 101 } 102 mPolicyRuleFlags[mPosition] = policyRuleFlags; 103 mPosition++; 104 return this; 105 } 106 } 107 108 /** 109 * @param mccRule A 2-character or 3-character string which can be either MCC or MNC. The 110 * character 'E' is used as a wild char to match any digit. 111 * @param mcc A 2-character or 3-character string which can be either MCC or MNC. 112 * @return Whether the {@code mccRule} matches {@code mcc}. 113 * 114 * @hide 115 */ 116 @VisibleForTesting match(String mccRule, String mcc)117 public static boolean match(String mccRule, String mcc) { 118 if (mccRule.length() < mcc.length()) { 119 return false; 120 } 121 for (int i = 0; i < mccRule.length(); i++) { 122 // 'E' is the wild char to match any digit. 123 if (mccRule.charAt(i) == 'E' 124 || (i < mcc.length() && mccRule.charAt(i) == mcc.charAt(i))) { 125 continue; 126 } 127 return false; 128 } 129 return true; 130 } 131 EuiccRulesAuthTable(int[] policyRules, CarrierIdentifier[][] carrierIds, int[] policyRuleFlags)132 private EuiccRulesAuthTable(int[] policyRules, CarrierIdentifier[][] carrierIds, 133 int[] policyRuleFlags) { 134 mPolicyRules = policyRules; 135 mCarrierIds = carrierIds; 136 mPolicyRuleFlags = policyRuleFlags; 137 } 138 139 /** 140 * Finds the index of the first authorisation rule matching the given policy and carrier id. If 141 * the returned index is not negative, the carrier is allowed to apply this policy to its 142 * profile. 143 * 144 * @param policy The policy rule. 145 * @param carrierId The carrier id. 146 * @return The index of authorization rule. If no rule is found, -1 will be returned. 147 */ findIndex(@uiccProfileInfo.PolicyRule int policy, CarrierIdentifier carrierId)148 public int findIndex(@EuiccProfileInfo.PolicyRule int policy, CarrierIdentifier carrierId) { 149 for (int i = 0; i < mPolicyRules.length; i++) { 150 if ((mPolicyRules[i] & policy) == 0) { 151 continue; 152 } 153 CarrierIdentifier[] carrierIds = mCarrierIds[i]; 154 if (carrierIds == null || carrierIds.length == 0) { 155 continue; 156 } 157 for (int j = 0; j < carrierIds.length; j++) { 158 CarrierIdentifier ruleCarrierId = carrierIds[j]; 159 if (!match(ruleCarrierId.getMcc(), carrierId.getMcc()) 160 || !match(ruleCarrierId.getMnc(), carrierId.getMnc())) { 161 continue; 162 } 163 String gid = ruleCarrierId.getGid1(); 164 if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid1())) { 165 continue; 166 } 167 gid = ruleCarrierId.getGid2(); 168 if (!TextUtils.isEmpty(gid) && !gid.equals(carrierId.getGid2())) { 169 continue; 170 } 171 return i; 172 } 173 } 174 return -1; 175 } 176 177 /** 178 * Tests if the entry in the table has the given policy rule flag. 179 * 180 * @param index The index of the entry. 181 * @param flag The policy rule flag to be tested. 182 * @throws ArrayIndexOutOfBoundsException If the {@code index} is negative or larger than the 183 * size of this table. 184 */ hasPolicyRuleFlag(int index, @PolicyRuleFlag int flag)185 public boolean hasPolicyRuleFlag(int index, @PolicyRuleFlag int flag) { 186 if (index < 0 || index >= mPolicyRules.length) { 187 throw new ArrayIndexOutOfBoundsException(index); 188 } 189 return (mPolicyRuleFlags[index] & flag) != 0; 190 } 191 192 @Override describeContents()193 public int describeContents() { 194 return 0; 195 } 196 197 @Override writeToParcel(Parcel dest, int flags)198 public void writeToParcel(Parcel dest, int flags) { 199 dest.writeIntArray(mPolicyRules); 200 for (CarrierIdentifier[] ids : mCarrierIds) { 201 dest.writeTypedArray(ids, flags); 202 } 203 dest.writeIntArray(mPolicyRuleFlags); 204 } 205 206 @Override equals(@ullable Object obj)207 public boolean equals(@Nullable Object obj) { 208 if (this == obj) { 209 return true; 210 } 211 if (obj == null || getClass() != obj.getClass()) { 212 return false; 213 } 214 215 EuiccRulesAuthTable that = (EuiccRulesAuthTable) obj; 216 if (mCarrierIds.length != that.mCarrierIds.length) { 217 return false; 218 } 219 for (int i = 0; i < mCarrierIds.length; i++) { 220 CarrierIdentifier[] carrierIds = mCarrierIds[i]; 221 CarrierIdentifier[] thatCarrierIds = that.mCarrierIds[i]; 222 if (carrierIds != null && thatCarrierIds != null) { 223 if (carrierIds.length != thatCarrierIds.length) { 224 return false; 225 } 226 for (int j = 0; j < carrierIds.length; j++) { 227 if (!carrierIds[j].equals(thatCarrierIds[j])) { 228 return false; 229 } 230 } 231 continue; 232 } else if (carrierIds == null && thatCarrierIds == null) { 233 continue; 234 } 235 return false; 236 } 237 238 return Arrays.equals(mPolicyRules, that.mPolicyRules) 239 && Arrays.equals(mPolicyRuleFlags, that.mPolicyRuleFlags); 240 } 241 EuiccRulesAuthTable(Parcel source)242 private EuiccRulesAuthTable(Parcel source) { 243 mPolicyRules = source.createIntArray(); 244 int len = mPolicyRules.length; 245 mCarrierIds = new CarrierIdentifier[len][]; 246 for (int i = 0; i < len; i++) { 247 mCarrierIds[i] = source.createTypedArray(CarrierIdentifier.CREATOR); 248 } 249 mPolicyRuleFlags = source.createIntArray(); 250 } 251 252 public static final @android.annotation.NonNull Creator<EuiccRulesAuthTable> CREATOR = 253 new Creator<EuiccRulesAuthTable>() { 254 @Override 255 public EuiccRulesAuthTable createFromParcel(Parcel source) { 256 return new EuiccRulesAuthTable(source); 257 } 258 259 @Override 260 public EuiccRulesAuthTable[] newArray(int size) { 261 return new EuiccRulesAuthTable[size]; 262 } 263 }; 264 } 265