1 /* 2 * Copyright (C) 2019 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 com.android.internal.compat; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 27 /** 28 * This class contains all the possible override allowed states. 29 */ 30 public final class OverrideAllowedState implements Parcelable { 31 @IntDef({ 32 ALLOWED, 33 DISABLED_NOT_DEBUGGABLE, 34 DISABLED_NON_TARGET_SDK, 35 DISABLED_TARGET_SDK_TOO_HIGH, 36 DEFERRED_VERIFICATION, 37 LOGGING_ONLY_CHANGE, 38 PLATFORM_TOO_OLD 39 }) 40 @Retention(RetentionPolicy.SOURCE) 41 public @interface State { 42 } 43 44 /** 45 * Change can be overridden. 46 */ 47 public static final int ALLOWED = 0; 48 /** 49 * Change cannot be overridden, due to the app not being debuggable. 50 */ 51 public static final int DISABLED_NOT_DEBUGGABLE = 1; 52 /** 53 * Change cannot be overridden, due to the build being non-debuggable and the change being 54 * enabled regardless of targetSdk. 55 */ 56 public static final int DISABLED_NON_TARGET_SDK = 2; 57 /** 58 * Change cannot be overridden, due to the app's targetSdk being above the change's targetSdk. 59 */ 60 public static final int DISABLED_TARGET_SDK_TOO_HIGH = 3; 61 /** 62 * Change override decision is currently being deferred, due to the app not being installed yet. 63 */ 64 public static final int DEFERRED_VERIFICATION = 4; 65 /** 66 * Change is marked as logging only, and cannot be toggled. 67 */ 68 public static final int LOGGING_ONLY_CHANGE = 5; 69 /** 70 * Change is gated by a target sdk version newer than the current platform sdk version. 71 */ 72 public static final int PLATFORM_TOO_OLD = 6; 73 74 @State 75 public final int state; 76 public final int appTargetSdk; 77 public final int changeIdTargetSdk; 78 OverrideAllowedState(Parcel parcel)79 private OverrideAllowedState(Parcel parcel) { 80 state = parcel.readInt(); 81 appTargetSdk = parcel.readInt(); 82 changeIdTargetSdk = parcel.readInt(); 83 } 84 OverrideAllowedState(@tate int state, int appTargetSdk, int changeIdTargetSdk)85 public OverrideAllowedState(@State int state, int appTargetSdk, int changeIdTargetSdk) { 86 this.state = state; 87 this.appTargetSdk = appTargetSdk; 88 this.changeIdTargetSdk = changeIdTargetSdk; 89 } 90 91 @Override describeContents()92 public int describeContents() { 93 return 0; 94 } 95 96 @Override writeToParcel(Parcel out, int flags)97 public void writeToParcel(Parcel out, int flags) { 98 out.writeInt(state); 99 out.writeInt(appTargetSdk); 100 out.writeInt(changeIdTargetSdk); 101 } 102 103 /** 104 * Enforces the policy for overriding compat changes. 105 * 106 * @param changeId the change id that was attempted to be overridden. 107 * @param packageName the package for which the attempt was made. 108 * @throws SecurityException if the policy forbids this operation. 109 */ enforce(long changeId, String packageName)110 public void enforce(long changeId, String packageName) 111 throws SecurityException { 112 switch (state) { 113 case ALLOWED: 114 case DEFERRED_VERIFICATION: 115 return; 116 case DISABLED_NOT_DEBUGGABLE: 117 throw new SecurityException( 118 "Cannot override a change on a non-debuggable app and user build."); 119 case DISABLED_NON_TARGET_SDK: 120 throw new SecurityException( 121 "Cannot override a default enabled/disabled change on a user build."); 122 case DISABLED_TARGET_SDK_TOO_HIGH: 123 throw new SecurityException(String.format( 124 "Cannot override %1$d for %2$s because the app's targetSdk (%3$d) is " 125 + "above the change's targetSdk threshold (%4$d)", 126 changeId, packageName, appTargetSdk, changeIdTargetSdk)); 127 case LOGGING_ONLY_CHANGE: 128 throw new SecurityException(String.format( 129 "Cannot override %1$d because it is marked as a logging-only change.", 130 changeId)); 131 case PLATFORM_TOO_OLD: 132 throw new SecurityException(String.format( 133 "Cannot override %1$d for %2$s because the change's targetSdk threshold " 134 + "(%3$d) is above the platform sdk.", 135 changeId, packageName, changeIdTargetSdk)); 136 } 137 } 138 139 public static final @NonNull 140 Parcelable.Creator<OverrideAllowedState> CREATOR = 141 new Parcelable.Creator<OverrideAllowedState>() { 142 public OverrideAllowedState createFromParcel(Parcel parcel) { 143 OverrideAllowedState info = new OverrideAllowedState(parcel); 144 return info; 145 } 146 147 public OverrideAllowedState[] newArray(int size) { 148 return new OverrideAllowedState[size]; 149 } 150 }; 151 152 @Override equals(Object obj)153 public boolean equals(Object obj) { 154 if (this == obj) { 155 return true; 156 } 157 if (obj == null) { 158 return false; 159 } 160 if (!(obj instanceof OverrideAllowedState)) { 161 return false; 162 } 163 OverrideAllowedState otherState = (OverrideAllowedState) obj; 164 return state == otherState.state 165 && appTargetSdk == otherState.appTargetSdk 166 && changeIdTargetSdk == otherState.changeIdTargetSdk; 167 } 168 stateName()169 private String stateName() { 170 switch (state) { 171 case ALLOWED: 172 return "ALLOWED"; 173 case DISABLED_NOT_DEBUGGABLE: 174 return "DISABLED_NOT_DEBUGGABLE"; 175 case DISABLED_NON_TARGET_SDK: 176 return "DISABLED_NON_TARGET_SDK"; 177 case DISABLED_TARGET_SDK_TOO_HIGH: 178 return "DISABLED_TARGET_SDK_TOO_HIGH"; 179 case DEFERRED_VERIFICATION: 180 return "DEFERRED_VERIFICATION"; 181 case LOGGING_ONLY_CHANGE: 182 return "LOGGING_ONLY_CHANGE"; 183 case PLATFORM_TOO_OLD: 184 return "PLATFORM_TOO_OLD"; 185 } 186 return "UNKNOWN"; 187 } 188 189 @Override toString()190 public String toString() { 191 return "OverrideAllowedState(state=" + stateName() + "; appTargetSdk=" + appTargetSdk 192 + "; changeIdTargetSdk=" + changeIdTargetSdk + ")"; 193 } 194 } 195