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.server.compat; 18 19 import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD; 20 import static android.content.pm.PackageManager.MATCH_ANY_USER; 21 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 22 23 import static com.android.internal.compat.OverrideAllowedState.ALLOWED; 24 import static com.android.internal.compat.OverrideAllowedState.DEFERRED_VERIFICATION; 25 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK; 26 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE; 27 import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH; 28 import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE; 29 import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD; 30 31 import android.annotation.NonNull; 32 import android.content.Context; 33 import android.content.pm.ApplicationInfo; 34 import android.content.pm.PackageManager; 35 import android.content.pm.PackageManager.NameNotFoundException; 36 import android.database.ContentObserver; 37 import android.os.Handler; 38 import android.provider.Settings; 39 40 import com.android.internal.annotations.VisibleForTesting; 41 import com.android.internal.compat.AndroidBuildClassifier; 42 import com.android.internal.compat.IOverrideValidator; 43 import com.android.internal.compat.OverrideAllowedState; 44 45 /** 46 * Implementation of the policy for allowing compat change overrides. 47 */ 48 public class OverrideValidatorImpl extends IOverrideValidator.Stub { 49 50 private AndroidBuildClassifier mAndroidBuildClassifier; 51 private Context mContext; 52 private CompatConfig mCompatConfig; 53 private boolean mForceNonDebuggableFinalBuild; 54 55 private class SettingsObserver extends ContentObserver { SettingsObserver()56 SettingsObserver() { 57 super(new Handler()); 58 } 59 @Override onChange(boolean selfChange)60 public void onChange(boolean selfChange) { 61 mForceNonDebuggableFinalBuild = Settings.Global.getInt( 62 mContext.getContentResolver(), 63 Settings.Global.FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT, 64 0) == 1; 65 } 66 } 67 68 @VisibleForTesting OverrideValidatorImpl(AndroidBuildClassifier androidBuildClassifier, Context context, CompatConfig config)69 OverrideValidatorImpl(AndroidBuildClassifier androidBuildClassifier, 70 Context context, CompatConfig config) { 71 mAndroidBuildClassifier = androidBuildClassifier; 72 mContext = context; 73 mCompatConfig = config; 74 mForceNonDebuggableFinalBuild = false; 75 } 76 77 /** 78 * Check the allowed state for the given changeId and packageName on a recheck. 79 * 80 * <p>Recheck happens when the given app is getting updated. In this case we cannot do a 81 * permission check on the caller, so we're using the fact that the override was present as 82 * proof that the original caller was allowed to set this override. 83 */ getOverrideAllowedStateForRecheck(long changeId, @NonNull String packageName)84 OverrideAllowedState getOverrideAllowedStateForRecheck(long changeId, 85 @NonNull String packageName) { 86 return getOverrideAllowedStateInternal(changeId, packageName, true); 87 } 88 89 @Override getOverrideAllowedState(long changeId, String packageName)90 public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) { 91 return getOverrideAllowedStateInternal(changeId, packageName, false); 92 } 93 getOverrideAllowedStateInternal(long changeId, String packageName, boolean isRecheck)94 private OverrideAllowedState getOverrideAllowedStateInternal(long changeId, String packageName, 95 boolean isRecheck) { 96 if (mCompatConfig.isLoggingOnly(changeId)) { 97 return new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1); 98 } 99 100 boolean debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild() 101 && !mForceNonDebuggableFinalBuild; 102 boolean finalBuild = mAndroidBuildClassifier.isFinalBuild() 103 || mForceNonDebuggableFinalBuild; 104 int maxTargetSdk = mCompatConfig.maxTargetSdkForChangeIdOptIn(changeId); 105 boolean disabled = mCompatConfig.isDisabled(changeId); 106 107 // Allow any override for userdebug or eng builds. 108 if (debuggableBuild) { 109 return new OverrideAllowedState(ALLOWED, -1, -1); 110 } 111 if (maxTargetSdk >= mAndroidBuildClassifier.platformTargetSdk()) { 112 return new OverrideAllowedState(PLATFORM_TOO_OLD, -1, maxTargetSdk); 113 } 114 PackageManager packageManager = mContext.getPackageManager(); 115 if (packageManager == null) { 116 throw new IllegalStateException("No PackageManager!"); 117 } 118 ApplicationInfo applicationInfo; 119 try { 120 applicationInfo = packageManager.getApplicationInfo(packageName, MATCH_ANY_USER); 121 } catch (NameNotFoundException e) { 122 return new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1); 123 } 124 // If the change is annotated as @Overridable, apps with the specific permission can 125 // set the override even on production builds. When rechecking the override, e.g. during an 126 // app update we can bypass this check, as it wouldn't have been here in the first place. 127 if (mCompatConfig.isOverridable(changeId) 128 && (isRecheck 129 || mContext.checkCallingOrSelfPermission( 130 OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) 131 == PERMISSION_GRANTED)) { 132 return new OverrideAllowedState(ALLOWED, -1, -1); 133 } 134 int appTargetSdk = applicationInfo.targetSdkVersion; 135 // Only allow overriding debuggable apps. 136 if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) { 137 return new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1); 138 } 139 // Allow overriding any change for debuggable apps on non-final builds. 140 if (!finalBuild) { 141 return new OverrideAllowedState(ALLOWED, appTargetSdk, maxTargetSdk); 142 } 143 // Do not allow overriding default enabled changes on user builds 144 if (maxTargetSdk == -1 && !disabled) { 145 return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, maxTargetSdk); 146 } 147 // Only allow to opt-in for a targetSdk gated change. 148 if (disabled || appTargetSdk <= maxTargetSdk) { 149 return new OverrideAllowedState(ALLOWED, appTargetSdk, maxTargetSdk); 150 } 151 return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, maxTargetSdk); 152 } 153 registerContentObserver()154 void registerContentObserver() { 155 mContext.getContentResolver().registerContentObserver( 156 Settings.Global.getUriFor( 157 Settings.Global.FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT), 158 false, 159 new SettingsObserver()); 160 } 161 forceNonDebuggableFinalForTest(boolean value)162 void forceNonDebuggableFinalForTest(boolean value) { 163 mForceNonDebuggableFinalBuild = value; 164 } 165 } 166