1 /* 2 * Copyright (C) 2008 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 android.content.pm; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.StringRes; 23 import android.annotation.SystemApi; 24 import android.annotation.TestApi; 25 import android.compat.annotation.UnsupportedAppUsage; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.text.TextUtils; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 33 /** 34 * Information you can retrieve about a particular security permission 35 * known to the system. This corresponds to information collected from the 36 * AndroidManifest.xml's <permission> tags. 37 */ 38 public class PermissionInfo extends PackageItemInfo implements Parcelable { 39 /** 40 * A normal application value for {@link #protectionLevel}, corresponding 41 * to the <code>normal</code> value of 42 * {@link android.R.attr#protectionLevel}. 43 */ 44 public static final int PROTECTION_NORMAL = 0; 45 46 /** 47 * Dangerous value for {@link #protectionLevel}, corresponding 48 * to the <code>dangerous</code> value of 49 * {@link android.R.attr#protectionLevel}. 50 */ 51 public static final int PROTECTION_DANGEROUS = 1; 52 53 /** 54 * System-level value for {@link #protectionLevel}, corresponding 55 * to the <code>signature</code> value of 56 * {@link android.R.attr#protectionLevel}. 57 */ 58 public static final int PROTECTION_SIGNATURE = 2; 59 60 /** 61 * @deprecated Use {@link #PROTECTION_SIGNATURE}|{@link #PROTECTION_FLAG_PRIVILEGED} 62 * instead. 63 */ 64 @Deprecated 65 public static final int PROTECTION_SIGNATURE_OR_SYSTEM = 3; 66 67 /** @hide */ 68 @IntDef(flag = false, prefix = { "PROTECTION_" }, value = { 69 PROTECTION_NORMAL, 70 PROTECTION_DANGEROUS, 71 PROTECTION_SIGNATURE, 72 PROTECTION_SIGNATURE_OR_SYSTEM, 73 }) 74 @Retention(RetentionPolicy.SOURCE) 75 public @interface Protection {} 76 77 /** 78 * Additional flag for {@link #protectionLevel}, corresponding 79 * to the <code>privileged</code> value of 80 * {@link android.R.attr#protectionLevel}. 81 */ 82 public static final int PROTECTION_FLAG_PRIVILEGED = 0x10; 83 84 /** 85 * @deprecated Old name for {@link #PROTECTION_FLAG_PRIVILEGED}, which 86 * is now very confusing because it only applies to privileged apps, not all 87 * apps on the system image. 88 */ 89 @Deprecated 90 public static final int PROTECTION_FLAG_SYSTEM = 0x10; 91 92 /** 93 * Additional flag for {@link #protectionLevel}, corresponding 94 * to the <code>development</code> value of 95 * {@link android.R.attr#protectionLevel}. 96 */ 97 public static final int PROTECTION_FLAG_DEVELOPMENT = 0x20; 98 99 /** 100 * Additional flag for {@link #protectionLevel}, corresponding 101 * to the <code>appop</code> value of 102 * {@link android.R.attr#protectionLevel}. 103 */ 104 public static final int PROTECTION_FLAG_APPOP = 0x40; 105 106 /** 107 * Additional flag for {@link #protectionLevel}, corresponding 108 * to the <code>pre23</code> value of 109 * {@link android.R.attr#protectionLevel}. 110 */ 111 public static final int PROTECTION_FLAG_PRE23 = 0x80; 112 113 /** 114 * Additional flag for {@link #protectionLevel}, corresponding 115 * to the <code>installer</code> value of 116 * {@link android.R.attr#protectionLevel}. 117 */ 118 public static final int PROTECTION_FLAG_INSTALLER = 0x100; 119 120 /** 121 * Additional flag for {@link #protectionLevel}, corresponding 122 * to the <code>verifier</code> value of 123 * {@link android.R.attr#protectionLevel}. 124 */ 125 public static final int PROTECTION_FLAG_VERIFIER = 0x200; 126 127 /** 128 * Additional flag for {@link #protectionLevel}, corresponding 129 * to the <code>preinstalled</code> value of 130 * {@link android.R.attr#protectionLevel}. 131 */ 132 public static final int PROTECTION_FLAG_PREINSTALLED = 0x400; 133 134 /** 135 * Additional flag for {@link #protectionLevel}, corresponding 136 * to the <code>setup</code> value of 137 * {@link android.R.attr#protectionLevel}. 138 */ 139 public static final int PROTECTION_FLAG_SETUP = 0x800; 140 141 /** 142 * Additional flag for {@link #protectionLevel}, corresponding 143 * to the <code>instant</code> value of 144 * {@link android.R.attr#protectionLevel}. 145 */ 146 public static final int PROTECTION_FLAG_INSTANT = 0x1000; 147 148 /** 149 * Additional flag for {@link #protectionLevel}, corresponding 150 * to the <code>runtime</code> value of 151 * {@link android.R.attr#protectionLevel}. 152 */ 153 public static final int PROTECTION_FLAG_RUNTIME_ONLY = 0x2000; 154 155 /** 156 * Additional flag for {@link #protectionLevel}, corresponding 157 * to the <code>oem</code> value of 158 * {@link android.R.attr#protectionLevel}. 159 * 160 * @hide 161 */ 162 @SystemApi 163 @TestApi 164 public static final int PROTECTION_FLAG_OEM = 0x4000; 165 166 /** 167 * Additional flag for {${link #protectionLevel}, corresponding 168 * to the <code>vendorPrivileged</code> value of 169 * {@link android.R.attr#protectionLevel}. 170 * 171 * @hide 172 */ 173 @TestApi 174 public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 0x8000; 175 176 /** 177 * Additional flag for {@link #protectionLevel}, corresponding 178 * to the <code>text_classifier</code> value of 179 * {@link android.R.attr#protectionLevel}. 180 * 181 * @hide 182 */ 183 @SystemApi 184 @TestApi 185 public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 0x10000; 186 187 /** 188 * Additional flag for {${link #protectionLevel}, corresponding 189 * to the <code>wellbeing</code> value of 190 * {@link android.R.attr#protectionLevel}. 191 * 192 * @hide 193 */ 194 @SystemApi 195 @TestApi 196 public static final int PROTECTION_FLAG_WELLBEING = 0x20000; 197 198 /** 199 * Additional flag for {@link #protectionLevel}, corresponding to the 200 * {@code documenter} value of {@link android.R.attr#protectionLevel}. 201 * 202 * @hide 203 */ 204 @SystemApi 205 @TestApi 206 public static final int PROTECTION_FLAG_DOCUMENTER = 0x40000; 207 208 /** 209 * Additional flag for {@link #protectionLevel}, corresponding to the 210 * {@code configurator} value of {@link android.R.attr#protectionLevel}. 211 * 212 * @hide 213 */ 214 @SystemApi 215 @TestApi 216 public static final int PROTECTION_FLAG_CONFIGURATOR = 0x80000; 217 218 /** 219 * Additional flag for {${link #protectionLevel}, corresponding 220 * to the <code>incident_report_approver</code> value of 221 * {@link android.R.attr#protectionLevel}. 222 * 223 * @hide 224 */ 225 @SystemApi 226 @TestApi 227 public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 0x100000; 228 229 /** 230 * Additional flag for {@link #protectionLevel}, corresponding 231 * to the <code>app_predictor</code> value of 232 * {@link android.R.attr#protectionLevel}. 233 * 234 * @hide 235 */ 236 @SystemApi 237 @TestApi 238 public static final int PROTECTION_FLAG_APP_PREDICTOR = 0x200000; 239 240 /** 241 * Additional flag for {@link #protectionLevel}, corresponding 242 * to the <code>companion</code> value of 243 * {@link android.R.attr#protectionLevel}. 244 * 245 * @hide 246 */ 247 @SystemApi 248 @TestApi 249 public static final int PROTECTION_FLAG_COMPANION = 0x800000; 250 251 /** 252 * Additional flag for {@link #protectionLevel}, corresponding 253 * to the <code>retailDemo</code> value of 254 * {@link android.R.attr#protectionLevel}. 255 * 256 * @hide 257 */ 258 @SystemApi 259 @TestApi 260 public static final int PROTECTION_FLAG_RETAIL_DEMO = 0x1000000; 261 262 /** @hide */ 263 @IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = { 264 PROTECTION_FLAG_PRIVILEGED, 265 PROTECTION_FLAG_SYSTEM, 266 PROTECTION_FLAG_DEVELOPMENT, 267 PROTECTION_FLAG_APPOP, 268 PROTECTION_FLAG_PRE23, 269 PROTECTION_FLAG_INSTALLER, 270 PROTECTION_FLAG_VERIFIER, 271 PROTECTION_FLAG_PREINSTALLED, 272 PROTECTION_FLAG_SETUP, 273 PROTECTION_FLAG_INSTANT, 274 PROTECTION_FLAG_RUNTIME_ONLY, 275 PROTECTION_FLAG_OEM, 276 PROTECTION_FLAG_VENDOR_PRIVILEGED, 277 PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER, 278 PROTECTION_FLAG_WELLBEING, 279 PROTECTION_FLAG_DOCUMENTER, 280 PROTECTION_FLAG_CONFIGURATOR, 281 PROTECTION_FLAG_INCIDENT_REPORT_APPROVER, 282 PROTECTION_FLAG_APP_PREDICTOR, 283 PROTECTION_FLAG_COMPANION, 284 PROTECTION_FLAG_RETAIL_DEMO, 285 }) 286 @Retention(RetentionPolicy.SOURCE) 287 public @interface ProtectionFlags {} 288 289 /** 290 * Mask for {@link #protectionLevel}: the basic protection type. 291 * 292 * @deprecated Use #getProtection() instead. 293 */ 294 @Deprecated 295 public static final int PROTECTION_MASK_BASE = 0xf; 296 297 /** 298 * Mask for {@link #protectionLevel}: additional flag bits. 299 * 300 * @deprecated Use #getProtectionFlags() instead. 301 */ 302 @Deprecated 303 public static final int PROTECTION_MASK_FLAGS = 0xfff0; 304 305 /** 306 * The level of access this permission is protecting, as per 307 * {@link android.R.attr#protectionLevel}. Consists of 308 * a base permission type and zero or more flags. Use the following functions 309 * to extract them. 310 * 311 * <pre> 312 * int basePermissionType = permissionInfo.getProtection(); 313 * int permissionFlags = permissionInfo.getProtectionFlags(); 314 * </pre> 315 * 316 * <p></p>Base permission types are {@link #PROTECTION_NORMAL}, 317 * {@link #PROTECTION_DANGEROUS}, {@link #PROTECTION_SIGNATURE} 318 * and the deprecated {@link #PROTECTION_SIGNATURE_OR_SYSTEM}. 319 * Flags are listed under {@link android.R.attr#protectionLevel}. 320 * 321 * @deprecated Use #getProtection() and #getProtectionFlags() instead. 322 */ 323 @Deprecated 324 public int protectionLevel; 325 326 /** 327 * The group this permission is a part of, as per 328 * {@link android.R.attr#permissionGroup}. 329 */ 330 public @Nullable String group; 331 332 /** 333 * Flag for {@link #flags}, corresponding to <code>costsMoney</code> 334 * value of {@link android.R.attr#permissionFlags}. 335 */ 336 public static final int FLAG_COSTS_MONEY = 1<<0; 337 338 /** 339 * Flag for {@link #flags}, corresponding to <code>removed</code> 340 * value of {@link android.R.attr#permissionFlags}. 341 * @hide 342 */ 343 @TestApi 344 @SystemApi 345 public static final int FLAG_REMOVED = 1<<1; 346 347 /** 348 * Flag for {@link #flags}, corresponding to <code>hardRestricted</code> 349 * value of {@link android.R.attr#permissionFlags}. 350 * 351 * <p> This permission is restricted by the platform and it would be 352 * grantable only to apps that meet special criteria per platform 353 * policy. 354 */ 355 public static final int FLAG_HARD_RESTRICTED = 1<<2; 356 357 /** 358 * Flag for {@link #flags}, corresponding to <code>softRestricted</code> 359 * value of {@link android.R.attr#permissionFlags}. 360 * 361 * <p>This permission is restricted by the platform and it would be 362 * grantable in its full form to apps that meet special criteria 363 * per platform policy. Otherwise, a weaker form of the permission 364 * would be granted. The weak grant depends on the permission. 365 */ 366 public static final int FLAG_SOFT_RESTRICTED = 1<<3; 367 368 /** 369 * Flag for {@link #flags}, corresponding to <code>immutablyRestricted</code> 370 * value of {@link android.R.attr#permissionFlags}. 371 * 372 * <p>This permission is restricted immutably which means that its 373 * restriction state may be specified only on the first install of 374 * the app and will stay in this initial whitelist state until 375 * the app is uninstalled. 376 */ 377 public static final int FLAG_IMMUTABLY_RESTRICTED = 1<<4; 378 379 /** 380 * Flag for {@link #flags}, indicating that this permission has been 381 * installed into the system's globally defined permissions. 382 */ 383 public static final int FLAG_INSTALLED = 1<<30; 384 385 /** @hide */ 386 @IntDef(flag = true, prefix = { "FLAG_" }, value = { 387 FLAG_COSTS_MONEY, 388 FLAG_REMOVED, 389 FLAG_HARD_RESTRICTED, 390 FLAG_SOFT_RESTRICTED, 391 FLAG_IMMUTABLY_RESTRICTED, 392 FLAG_INSTALLED 393 }) 394 @Retention(RetentionPolicy.SOURCE) 395 public @interface Flags {} 396 397 /** 398 * Additional flags about this permission as given by 399 * {@link android.R.attr#permissionFlags}. 400 */ 401 public @Flags int flags; 402 403 /** 404 * A string resource identifier (in the package's resources) of this 405 * permission's description. From the "description" attribute or, 406 * if not set, 0. 407 */ 408 public @StringRes int descriptionRes; 409 410 /** 411 * A string resource identifier (in the package's resources) used to request the permissions. 412 * From the "request" attribute or, if not set, 0. 413 * 414 * @hide 415 */ 416 @SystemApi 417 public @StringRes int requestRes; 418 419 /** 420 * Some permissions only grant access while the app is in foreground. Some of these permissions 421 * allow to add background capabilities by adding another permission. 422 * 423 * If this is such a permission, this is the name of the permission adding the background 424 * access. 425 * 426 * From the "backgroundPermission" attribute or, if not set null 427 * 428 * @hide 429 */ 430 @SystemApi 431 @TestApi 432 public final @Nullable String backgroundPermission; 433 434 /** 435 * The description string provided in the AndroidManifest file, if any. You 436 * probably don't want to use this, since it will be null if the description 437 * is in a resource. You probably want 438 * {@link PermissionInfo#loadDescription} instead. 439 */ 440 public @Nullable CharSequence nonLocalizedDescription; 441 442 /** @hide */ fixProtectionLevel(int level)443 public static int fixProtectionLevel(int level) { 444 if (level == PROTECTION_SIGNATURE_OR_SYSTEM) { 445 level = PROTECTION_SIGNATURE | PROTECTION_FLAG_PRIVILEGED; 446 } 447 if ((level & PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0 448 && (level & PROTECTION_FLAG_PRIVILEGED) == 0) { 449 // 'vendorPrivileged' must be 'privileged'. If not, 450 // drop the vendorPrivileged. 451 level = level & ~PROTECTION_FLAG_VENDOR_PRIVILEGED; 452 } 453 return level; 454 } 455 456 /** @hide */ 457 @UnsupportedAppUsage protectionToString(int level)458 public static @NonNull String protectionToString(int level) { 459 String protLevel = "????"; 460 switch (level & PROTECTION_MASK_BASE) { 461 case PermissionInfo.PROTECTION_DANGEROUS: 462 protLevel = "dangerous"; 463 break; 464 case PermissionInfo.PROTECTION_NORMAL: 465 protLevel = "normal"; 466 break; 467 case PermissionInfo.PROTECTION_SIGNATURE: 468 protLevel = "signature"; 469 break; 470 case PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM: 471 protLevel = "signatureOrSystem"; 472 break; 473 } 474 if ((level & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) { 475 protLevel += "|privileged"; 476 } 477 if ((level & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) { 478 protLevel += "|development"; 479 } 480 if ((level & PermissionInfo.PROTECTION_FLAG_APPOP) != 0) { 481 protLevel += "|appop"; 482 } 483 if ((level & PermissionInfo.PROTECTION_FLAG_PRE23) != 0) { 484 protLevel += "|pre23"; 485 } 486 if ((level & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0) { 487 protLevel += "|installer"; 488 } 489 if ((level & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0) { 490 protLevel += "|verifier"; 491 } 492 if ((level & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0) { 493 protLevel += "|preinstalled"; 494 } 495 if ((level & PermissionInfo.PROTECTION_FLAG_SETUP) != 0) { 496 protLevel += "|setup"; 497 } 498 if ((level & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0) { 499 protLevel += "|instant"; 500 } 501 if ((level & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0) { 502 protLevel += "|runtime"; 503 } 504 if ((level & PermissionInfo.PROTECTION_FLAG_OEM) != 0) { 505 protLevel += "|oem"; 506 } 507 if ((level & PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0) { 508 protLevel += "|vendorPrivileged"; 509 } 510 if ((level & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0) { 511 protLevel += "|textClassifier"; 512 } 513 if ((level & PermissionInfo.PROTECTION_FLAG_WELLBEING) != 0) { 514 protLevel += "|wellbeing"; 515 } 516 if ((level & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0) { 517 protLevel += "|documenter"; 518 } 519 if ((level & PROTECTION_FLAG_CONFIGURATOR) != 0) { 520 protLevel += "|configurator"; 521 } 522 if ((level & PermissionInfo.PROTECTION_FLAG_INCIDENT_REPORT_APPROVER) != 0) { 523 protLevel += "|incidentReportApprover"; 524 } 525 if ((level & PermissionInfo.PROTECTION_FLAG_APP_PREDICTOR) != 0) { 526 protLevel += "|appPredictor"; 527 } 528 if ((level & PermissionInfo.PROTECTION_FLAG_COMPANION) != 0) { 529 protLevel += "|companion"; 530 } 531 if ((level & PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO) != 0) { 532 protLevel += "|retailDemo"; 533 } 534 return protLevel; 535 } 536 537 /** 538 * @hide 539 */ PermissionInfo(@ullable String backgroundPermission)540 public PermissionInfo(@Nullable String backgroundPermission) { 541 this.backgroundPermission = backgroundPermission; 542 } 543 544 /** 545 * @deprecated Should only be created by the system. 546 */ 547 @Deprecated PermissionInfo()548 public PermissionInfo() { 549 this((String) null); 550 } 551 552 /** 553 * @deprecated Should only be created by the system. 554 */ 555 @Deprecated PermissionInfo(@onNull PermissionInfo orig)556 public PermissionInfo(@NonNull PermissionInfo orig) { 557 super(orig); 558 protectionLevel = orig.protectionLevel; 559 flags = orig.flags; 560 group = orig.group; 561 backgroundPermission = orig.backgroundPermission; 562 descriptionRes = orig.descriptionRes; 563 requestRes = orig.requestRes; 564 nonLocalizedDescription = orig.nonLocalizedDescription; 565 } 566 567 /** 568 * Retrieve the textual description of this permission. This 569 * will call back on the given PackageManager to load the description from 570 * the application. 571 * 572 * @param pm A PackageManager from which the label can be loaded; usually 573 * the PackageManager from which you originally retrieved this item. 574 * 575 * @return Returns a CharSequence containing the permission's description. 576 * If there is no description, null is returned. 577 */ loadDescription(@onNull PackageManager pm)578 public @Nullable CharSequence loadDescription(@NonNull PackageManager pm) { 579 if (nonLocalizedDescription != null) { 580 return nonLocalizedDescription; 581 } 582 if (descriptionRes != 0) { 583 CharSequence label = pm.getText(packageName, descriptionRes, null); 584 if (label != null) { 585 return label; 586 } 587 } 588 return null; 589 } 590 591 /** 592 * Return the base permission type. 593 */ 594 @Protection getProtection()595 public int getProtection() { 596 return protectionLevel & PROTECTION_MASK_BASE; 597 } 598 599 /** 600 * Return the additional flags in {@link #protectionLevel}. 601 */ 602 @ProtectionFlags getProtectionFlags()603 public int getProtectionFlags() { 604 return protectionLevel & ~PROTECTION_MASK_BASE; 605 } 606 607 @Override toString()608 public String toString() { 609 return "PermissionInfo{" 610 + Integer.toHexString(System.identityHashCode(this)) 611 + " " + name + "}"; 612 } 613 614 @Override describeContents()615 public int describeContents() { 616 return 0; 617 } 618 619 @Override writeToParcel(Parcel dest, int parcelableFlags)620 public void writeToParcel(Parcel dest, int parcelableFlags) { 621 super.writeToParcel(dest, parcelableFlags); 622 dest.writeInt(protectionLevel); 623 dest.writeInt(flags); 624 dest.writeString8(group); 625 dest.writeString8(backgroundPermission); 626 dest.writeInt(descriptionRes); 627 dest.writeInt(requestRes); 628 TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags); 629 } 630 631 /** @hide */ calculateFootprint()632 public int calculateFootprint() { 633 int size = name.length(); 634 if (nonLocalizedLabel != null) { 635 size += nonLocalizedLabel.length(); 636 } 637 if (nonLocalizedDescription != null) { 638 size += nonLocalizedDescription.length(); 639 } 640 return size; 641 } 642 643 /** @hide */ isHardRestricted()644 public boolean isHardRestricted() { 645 return (flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0; 646 } 647 648 /** @hide */ isSoftRestricted()649 public boolean isSoftRestricted() { 650 return (flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0; 651 } 652 653 /** @hide */ isRestricted()654 public boolean isRestricted() { 655 return isHardRestricted() || isSoftRestricted(); 656 } 657 658 /** @hide */ isAppOp()659 public boolean isAppOp() { 660 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0; 661 } 662 663 /** @hide */ isRuntime()664 public boolean isRuntime() { 665 return getProtection() == PROTECTION_DANGEROUS; 666 } 667 668 public static final @NonNull Creator<PermissionInfo> CREATOR = 669 new Creator<PermissionInfo>() { 670 @Override 671 public PermissionInfo createFromParcel(Parcel source) { 672 return new PermissionInfo(source); 673 } 674 @Override 675 public PermissionInfo[] newArray(int size) { 676 return new PermissionInfo[size]; 677 } 678 }; 679 PermissionInfo(Parcel source)680 private PermissionInfo(Parcel source) { 681 super(source); 682 protectionLevel = source.readInt(); 683 flags = source.readInt(); 684 group = source.readString8(); 685 backgroundPermission = source.readString8(); 686 descriptionRes = source.readInt(); 687 requestRes = source.readInt(); 688 nonLocalizedDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 689 } 690 } 691