1 /* 2 * Copyright (C) 2017 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 com.android.internal.telephony.euicc; 17 18 import android.annotation.IntDef; 19 import android.annotation.Nullable; 20 import android.app.PendingIntent; 21 import android.os.Binder; 22 import android.os.Bundle; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.service.euicc.EuiccService; 26 import android.telephony.euicc.DownloadableSubscription; 27 import android.telephony.euicc.EuiccManager; 28 import android.text.TextUtils; 29 import android.util.Log; 30 31 import com.android.internal.annotations.VisibleForTesting; 32 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 36 /** 37 * Representation of an {@link EuiccController} operation which failed with a resolvable error. 38 * 39 * <p>This class tracks the operation which failed and the reason for failure. Once the error is 40 * resolved, the operation can be resumed with {@link #continueOperation}. 41 */ 42 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 43 public class EuiccOperation implements Parcelable { 44 private static final String TAG = "EuiccOperation"; 45 46 public static final Creator<EuiccOperation> CREATOR = new Creator<EuiccOperation>() { 47 @Override 48 public EuiccOperation createFromParcel(Parcel in) { 49 return new EuiccOperation(in); 50 } 51 52 @Override 53 public EuiccOperation[] newArray(int size) { 54 return new EuiccOperation[size]; 55 } 56 }; 57 58 @VisibleForTesting 59 @Retention(RetentionPolicy.SOURCE) 60 @IntDef({ 61 ACTION_GET_METADATA_DEACTIVATE_SIM, 62 ACTION_DOWNLOAD_DEACTIVATE_SIM, 63 ACTION_DOWNLOAD_NO_PRIVILEGES, 64 ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM, 65 ACTION_SWITCH_DEACTIVATE_SIM, 66 ACTION_SWITCH_NO_PRIVILEGES, 67 ACTION_DOWNLOAD_RESOLVABLE_ERRORS, 68 }) 69 @interface Action {} 70 71 @VisibleForTesting 72 static final int ACTION_GET_METADATA_DEACTIVATE_SIM = 1; 73 @VisibleForTesting 74 static final int ACTION_DOWNLOAD_DEACTIVATE_SIM = 2; 75 @VisibleForTesting 76 static final int ACTION_DOWNLOAD_NO_PRIVILEGES = 3; 77 @VisibleForTesting 78 static final int ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM = 4; 79 @VisibleForTesting 80 static final int ACTION_SWITCH_DEACTIVATE_SIM = 5; 81 @VisibleForTesting 82 static final int ACTION_SWITCH_NO_PRIVILEGES = 6; 83 @VisibleForTesting 84 static final int ACTION_DOWNLOAD_RESOLVABLE_ERRORS = 7; 85 /** 86 * @deprecated Use ACTION_DOWNLOAD_RESOLVABLE_ERRORS and pass the resolvable errors in bit map. 87 */ 88 @VisibleForTesting 89 @Deprecated 90 static final int ACTION_DOWNLOAD_CONFIRMATION_CODE = 8; 91 /** 92 * ACTION_DOWNLOAD_CHECK_METADATA can be used for either NO_PRIVILEGES or DEACTIVATE_SIM. 93 */ 94 @VisibleForTesting 95 static final int ACTION_DOWNLOAD_NO_PRIVILEGES_OR_DEACTIVATE_SIM_CHECK_METADATA = 9; 96 97 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 98 public final @Action int mAction; 99 100 private final long mCallingToken; 101 102 @Nullable 103 private final DownloadableSubscription mDownloadableSubscription; 104 private final int mSubscriptionId; 105 private final boolean mSwitchAfterDownload; 106 @Nullable 107 private final String mCallingPackage; 108 @Nullable 109 private final int mResolvableErrors; 110 111 /** 112 * {@link EuiccManager#getDownloadableSubscriptionMetadata} failed with 113 * {@link EuiccService#RESULT_MUST_DEACTIVATE_SIM}. 114 */ forGetMetadataDeactivateSim(long callingToken, DownloadableSubscription subscription, String callingPackage)115 static EuiccOperation forGetMetadataDeactivateSim(long callingToken, 116 DownloadableSubscription subscription, String callingPackage) { 117 return new EuiccOperation(ACTION_GET_METADATA_DEACTIVATE_SIM, callingToken, 118 subscription, 0 /* subscriptionId */, false /* switchAfterDownload */, 119 callingPackage); 120 } 121 122 /** 123 * {@link EuiccManager#downloadSubscription} failed with a mustDeactivateSim error. Should only 124 * be used for privileged callers; for unprivileged callers, use 125 * {@link #forDownloadNoPrivileges} to avoid a double prompt. 126 */ forDownloadDeactivateSim(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage)127 static EuiccOperation forDownloadDeactivateSim(long callingToken, 128 DownloadableSubscription subscription, boolean switchAfterDownload, 129 String callingPackage) { 130 return new EuiccOperation(ACTION_DOWNLOAD_DEACTIVATE_SIM, callingToken, 131 subscription, 0 /* subscriptionId */, switchAfterDownload, callingPackage); 132 } 133 134 /** 135 * {@link EuiccManager#downloadSubscription} failed because the calling app does not have 136 * permission to manage the current active subscription. 137 */ forDownloadNoPrivileges(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage)138 static EuiccOperation forDownloadNoPrivileges(long callingToken, 139 DownloadableSubscription subscription, boolean switchAfterDownload, 140 String callingPackage) { 141 return new EuiccOperation(ACTION_DOWNLOAD_NO_PRIVILEGES, callingToken, 142 subscription, 0 /* subscriptionId */, switchAfterDownload, callingPackage); 143 } 144 145 /** 146 * {@link EuiccManager#downloadSubscription} failed because the caller can't manage the target 147 * SIM, or we cannot determine the privileges without deactivating the current SIM first. 148 */ forDownloadNoPrivilegesOrDeactivateSimCheckMetadata(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage)149 static EuiccOperation forDownloadNoPrivilegesOrDeactivateSimCheckMetadata(long callingToken, 150 DownloadableSubscription subscription, boolean switchAfterDownload, 151 String callingPackage) { 152 return new EuiccOperation(ACTION_DOWNLOAD_NO_PRIVILEGES_OR_DEACTIVATE_SIM_CHECK_METADATA, 153 callingToken, subscription, 0 /* subscriptionId */, 154 switchAfterDownload, callingPackage); 155 } 156 157 /** 158 * {@link EuiccManager#downloadSubscription} failed with 159 * {@link EuiccService#RESULT_NEED_CONFIRMATION_CODE} error. 160 * 161 * @deprecated Use 162 * {@link #forDownloadResolvableErrors(long, DownloadableSubscription, boolean, String, int)} 163 * instead. 164 */ 165 @Deprecated forDownloadConfirmationCode(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage)166 public static EuiccOperation forDownloadConfirmationCode(long callingToken, 167 DownloadableSubscription subscription, boolean switchAfterDownload, 168 String callingPackage) { 169 return new EuiccOperation(ACTION_DOWNLOAD_CONFIRMATION_CODE, callingToken, 170 subscription, 0 /* subscriptionId */, switchAfterDownload, callingPackage); 171 } 172 173 /** 174 * {@link EuiccManager#downloadSubscription} failed with 175 * {@link EuiccService#RESULT_RESOLVABLE_ERRORS} error. 176 */ forDownloadResolvableErrors(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, int resolvableErrors)177 static EuiccOperation forDownloadResolvableErrors(long callingToken, 178 DownloadableSubscription subscription, boolean switchAfterDownload, 179 String callingPackage, int resolvableErrors) { 180 return new EuiccOperation(ACTION_DOWNLOAD_RESOLVABLE_ERRORS, callingToken, 181 subscription, 0 /* subscriptionId */, switchAfterDownload, 182 callingPackage, resolvableErrors); 183 } 184 forGetDefaultListDeactivateSim(long callingToken, String callingPackage)185 static EuiccOperation forGetDefaultListDeactivateSim(long callingToken, String callingPackage) { 186 return new EuiccOperation(ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM, callingToken, 187 null /* downloadableSubscription */, 0 /* subscriptionId */, 188 false /* switchAfterDownload */, callingPackage); 189 } 190 forSwitchDeactivateSim(long callingToken, int subscriptionId, String callingPackage)191 static EuiccOperation forSwitchDeactivateSim(long callingToken, int subscriptionId, 192 String callingPackage) { 193 return new EuiccOperation(ACTION_SWITCH_DEACTIVATE_SIM, callingToken, 194 null /* downloadableSubscription */, subscriptionId, 195 false /* switchAfterDownload */, callingPackage); 196 } 197 forSwitchNoPrivileges(long callingToken, int subscriptionId, String callingPackage)198 static EuiccOperation forSwitchNoPrivileges(long callingToken, int subscriptionId, 199 String callingPackage) { 200 return new EuiccOperation(ACTION_SWITCH_NO_PRIVILEGES, callingToken, 201 null /* downloadableSubscription */, subscriptionId, 202 false /* switchAfterDownload */, callingPackage); 203 } 204 EuiccOperation(@ction int action, long callingToken, @Nullable DownloadableSubscription downloadableSubscription, int subscriptionId, boolean switchAfterDownload, String callingPackage, int resolvableErrors)205 EuiccOperation(@Action int action, 206 long callingToken, 207 @Nullable DownloadableSubscription downloadableSubscription, 208 int subscriptionId, 209 boolean switchAfterDownload, 210 String callingPackage, 211 int resolvableErrors) { 212 mAction = action; 213 mCallingToken = callingToken; 214 mDownloadableSubscription = downloadableSubscription; 215 mSubscriptionId = subscriptionId; 216 mSwitchAfterDownload = switchAfterDownload; 217 mCallingPackage = callingPackage; 218 mResolvableErrors = resolvableErrors; 219 } 220 EuiccOperation(@ction int action, long callingToken, @Nullable DownloadableSubscription downloadableSubscription, int subscriptionId, boolean switchAfterDownload, String callingPackage)221 EuiccOperation(@Action int action, 222 long callingToken, 223 @Nullable DownloadableSubscription downloadableSubscription, 224 int subscriptionId, 225 boolean switchAfterDownload, 226 String callingPackage) { 227 mAction = action; 228 mCallingToken = callingToken; 229 mDownloadableSubscription = downloadableSubscription; 230 mSubscriptionId = subscriptionId; 231 mSwitchAfterDownload = switchAfterDownload; 232 mCallingPackage = callingPackage; 233 mResolvableErrors = 0; 234 } 235 EuiccOperation(Parcel in)236 EuiccOperation(Parcel in) { 237 mAction = in.readInt(); 238 mCallingToken = in.readLong(); 239 mDownloadableSubscription = in.readTypedObject(DownloadableSubscription.CREATOR); 240 mSubscriptionId = in.readInt(); 241 mSwitchAfterDownload = in.readBoolean(); 242 mCallingPackage = in.readString(); 243 mResolvableErrors = in.readInt(); 244 } 245 246 @Override writeToParcel(Parcel dest, int flags)247 public void writeToParcel(Parcel dest, int flags) { 248 dest.writeInt(mAction); 249 dest.writeLong(mCallingToken); 250 dest.writeTypedObject(mDownloadableSubscription, flags); 251 dest.writeInt(mSubscriptionId); 252 dest.writeBoolean(mSwitchAfterDownload); 253 dest.writeString(mCallingPackage); 254 dest.writeInt(mResolvableErrors); 255 } 256 257 /** 258 * Resume this operation based on the results of the resolution activity. 259 * 260 * @param resolutionExtras The resolution extras as provided to 261 * {@link EuiccManager#continueOperation}. 262 * @param callbackIntent The callback intent to trigger after the operation completes. 263 */ continueOperation(int cardId, Bundle resolutionExtras, PendingIntent callbackIntent)264 public void continueOperation(int cardId, Bundle resolutionExtras, 265 PendingIntent callbackIntent) { 266 // Restore the identity of the caller. We should err on the side of caution and redo any 267 // permission checks before continuing with the operation in case the caller state has 268 // changed. Resolution flows can re-clear the identity if required. 269 Binder.restoreCallingIdentity(mCallingToken); 270 271 switch (mAction) { 272 case ACTION_GET_METADATA_DEACTIVATE_SIM: 273 resolvedGetMetadataDeactivateSim(cardId, 274 resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), 275 callbackIntent); 276 break; 277 case ACTION_DOWNLOAD_DEACTIVATE_SIM: 278 resolvedDownloadDeactivateSim(cardId, 279 resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), 280 callbackIntent); 281 break; 282 case ACTION_DOWNLOAD_NO_PRIVILEGES: 283 resolvedDownloadNoPrivileges(cardId, 284 resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), 285 callbackIntent); 286 break; 287 case ACTION_DOWNLOAD_NO_PRIVILEGES_OR_DEACTIVATE_SIM_CHECK_METADATA: 288 resolvedDownloadNoPrivilegesOrDeactivateSimCheckMetadata(cardId, 289 resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), 290 callbackIntent); 291 break; 292 case ACTION_DOWNLOAD_CONFIRMATION_CODE: // Deprecated case 293 resolvedDownloadConfirmationCode(cardId, 294 resolutionExtras.getString(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE), 295 callbackIntent); 296 break; 297 case ACTION_DOWNLOAD_RESOLVABLE_ERRORS: 298 resolvedDownloadResolvableErrors(cardId, resolutionExtras, callbackIntent); 299 break; 300 case ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM: 301 resolvedGetDefaultListDeactivateSim(cardId, 302 resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), 303 callbackIntent); 304 break; 305 case ACTION_SWITCH_DEACTIVATE_SIM: 306 resolvedSwitchDeactivateSim(cardId, 307 resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), 308 callbackIntent); 309 break; 310 case ACTION_SWITCH_NO_PRIVILEGES: 311 resolvedSwitchNoPrivileges(cardId, 312 resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), 313 callbackIntent); 314 break; 315 default: 316 Log.wtf(TAG, "Unknown action: " + mAction); 317 break; 318 } 319 } 320 resolvedGetMetadataDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent)321 private void resolvedGetMetadataDeactivateSim(int cardId, boolean consent, 322 PendingIntent callbackIntent) { 323 if (consent) { 324 // User has consented; perform the lookup, but this time, tell the LPA to deactivate any 325 // required active SIMs. 326 EuiccController.get().getDownloadableSubscriptionMetadata( 327 cardId, 328 mDownloadableSubscription, 329 true /* forceDeactivateSim */, 330 mCallingPackage, 331 callbackIntent); 332 } else { 333 // User has not consented; fail the operation. 334 fail(callbackIntent); 335 } 336 } 337 resolvedDownloadDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent)338 private void resolvedDownloadDeactivateSim(int cardId, boolean consent, 339 PendingIntent callbackIntent) { 340 if (consent) { 341 // User has consented; perform the download, but this time, tell the LPA to deactivate 342 // any required active SIMs. 343 EuiccController.get().downloadSubscription( 344 cardId, 345 mDownloadableSubscription, 346 mSwitchAfterDownload, 347 mCallingPackage, 348 true /* forceDeactivateSim */, 349 null /* resolvedBundle */, 350 callbackIntent); 351 } else { 352 // User has not consented; fail the operation. 353 fail(callbackIntent); 354 } 355 } 356 resolvedDownloadNoPrivileges(int cardId, boolean consent, PendingIntent callbackIntent)357 private void resolvedDownloadNoPrivileges(int cardId, boolean consent, 358 PendingIntent callbackIntent) { 359 if (consent) { 360 // User has consented; perform the download with full privileges. 361 long token = Binder.clearCallingIdentity(); 362 try { 363 // Note: We turn on "forceDeactivateSim" here under the assumption that the 364 // privilege prompt should also cover permission to deactivate an active SIM, as 365 // the privilege prompt makes it clear that we're switching from the current 366 // carrier. 367 EuiccController.get().downloadSubscriptionPrivileged( 368 cardId, 369 token, 370 mDownloadableSubscription, 371 mSwitchAfterDownload, 372 true /* forceDeactivateSim */, 373 mCallingPackage, 374 null /* resolvedBundle */, 375 callbackIntent); 376 } finally { 377 Binder.restoreCallingIdentity(token); 378 } 379 } else { 380 // User has not consented; fail the operation. 381 fail(callbackIntent); 382 } 383 } 384 resolvedDownloadNoPrivilegesOrDeactivateSimCheckMetadata(int cardId, boolean consent, PendingIntent callbackIntent)385 private void resolvedDownloadNoPrivilegesOrDeactivateSimCheckMetadata(int cardId, 386 boolean consent, PendingIntent callbackIntent) { 387 if (consent) { 388 // User has consented; perform the download with full privileges. 389 long token = Binder.clearCallingIdentity(); 390 try { 391 // Note: We turn on "forceDeactivateSim" here under the assumption that the 392 // privilege prompt should also cover permission to deactivate an active SIM, as 393 // the privilege prompt makes it clear that we're switching from the current 394 // carrier. 395 EuiccController.get().downloadSubscriptionPrivilegedCheckMetadata( 396 cardId, 397 token, 398 mDownloadableSubscription, 399 mSwitchAfterDownload, 400 true /* forceDeactivateSim */, 401 mCallingPackage, 402 null /* resolvedBundle */, 403 callbackIntent); 404 } finally { 405 Binder.restoreCallingIdentity(token); 406 } 407 } else { 408 // User has not consented; fail the operation. 409 fail(callbackIntent); 410 } 411 } 412 413 /** 414 * @deprecated The resolvable errors in download step are solved by 415 * {@link #resolvedDownloadResolvableErrors(Bundle, PendingIntent)} from Q. 416 */ 417 @Deprecated resolvedDownloadConfirmationCode(int cardId, String confirmationCode, PendingIntent callbackIntent)418 private void resolvedDownloadConfirmationCode(int cardId, String confirmationCode, 419 PendingIntent callbackIntent) { 420 if (TextUtils.isEmpty(confirmationCode)) { 421 fail(callbackIntent); 422 } else { 423 mDownloadableSubscription.setConfirmationCode(confirmationCode); 424 EuiccController.get().downloadSubscription( 425 cardId, 426 mDownloadableSubscription, 427 mSwitchAfterDownload, 428 mCallingPackage, 429 true /* forceDeactivateSim */, 430 null, 431 callbackIntent); 432 } 433 } 434 resolvedDownloadResolvableErrors(int cardId, Bundle resolvedBundle, PendingIntent callbackIntent)435 private void resolvedDownloadResolvableErrors(int cardId, Bundle resolvedBundle, 436 PendingIntent callbackIntent) { 437 boolean pass = true; 438 String confirmationCode = null; 439 if ((mResolvableErrors & EuiccService.RESOLVABLE_ERROR_POLICY_RULES) != 0) { 440 if (!resolvedBundle.getBoolean(EuiccService.EXTRA_RESOLUTION_ALLOW_POLICY_RULES)) { 441 pass = false; 442 } 443 } 444 if ((mResolvableErrors & EuiccService.RESOLVABLE_ERROR_CONFIRMATION_CODE) != 0) { 445 confirmationCode = resolvedBundle.getString( 446 EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE); 447 // The check here just makes sure the entered confirmation code is non-empty. The actual 448 // check to valid the confirmation code is done by LPA on the ensuing download attemp. 449 if (TextUtils.isEmpty(confirmationCode)) { 450 pass = false; 451 } 452 } 453 454 if (!pass) { 455 fail(callbackIntent); 456 } else { 457 mDownloadableSubscription.setConfirmationCode(confirmationCode); 458 EuiccController.get().downloadSubscription( 459 cardId, 460 mDownloadableSubscription, 461 mSwitchAfterDownload, 462 mCallingPackage, 463 true /* forceDeactivateSim */, 464 resolvedBundle, 465 callbackIntent); 466 } 467 } 468 resolvedGetDefaultListDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent)469 private void resolvedGetDefaultListDeactivateSim(int cardId, boolean consent, 470 PendingIntent callbackIntent) { 471 if (consent) { 472 // User has consented; perform the lookup, but this time, tell the LPA to deactivate any 473 // required active SIMs. 474 EuiccController.get().getDefaultDownloadableSubscriptionList( 475 cardId, 476 true /* forceDeactivateSim */, 477 mCallingPackage, 478 callbackIntent); 479 } else { 480 // User has not consented; fail the operation. 481 fail(callbackIntent); 482 } 483 } 484 resolvedSwitchDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent)485 private void resolvedSwitchDeactivateSim(int cardId, boolean consent, 486 PendingIntent callbackIntent) { 487 if (consent) { 488 // User has consented; perform the switch, but this time, tell the LPA to deactivate any 489 // required active SIMs. 490 EuiccController.get().switchToSubscription( 491 cardId, 492 mSubscriptionId, 493 true /* forceDeactivateSim */, 494 mCallingPackage, 495 callbackIntent); 496 } else { 497 // User has not consented; fail the operation. 498 fail(callbackIntent); 499 } 500 } 501 resolvedSwitchNoPrivileges(int cardId, boolean consent, PendingIntent callbackIntent)502 private void resolvedSwitchNoPrivileges(int cardId, boolean consent, 503 PendingIntent callbackIntent) { 504 if (consent) { 505 // User has consented; perform the switch with full privileges. 506 long token = Binder.clearCallingIdentity(); 507 try { 508 // Note: We turn on "forceDeactivateSim" here under the assumption that the 509 // privilege prompt should also cover permission to deactivate an active SIM, as 510 // the privilege prompt makes it clear that we're switching from the current 511 // carrier. Also note that in practice, we'd need to deactivate the active SIM to 512 // even reach this point, because we cannot fetch the metadata needed to check the 513 // privileges without doing so. 514 EuiccController.get().switchToSubscriptionPrivileged( 515 cardId, 516 token, 517 mSubscriptionId, 518 true /* forceDeactivateSim */, 519 mCallingPackage, 520 callbackIntent); 521 } finally { 522 Binder.restoreCallingIdentity(token); 523 } 524 } else { 525 // User has not consented; fail the operation. 526 fail(callbackIntent); 527 } 528 } 529 fail(PendingIntent callbackIntent)530 private static void fail(PendingIntent callbackIntent) { 531 EuiccController.get().sendResult( 532 callbackIntent, 533 EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 534 null /* extrasIntent */); 535 } 536 537 @Override describeContents()538 public int describeContents() { 539 return 0; 540 } 541 } 542