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