1 /** 2 * Copyright (c) 2015, 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.notification; 18 19 import android.content.ComponentName; 20 import android.net.Uri; 21 import android.os.Binder; 22 import android.os.Process; 23 import android.os.UserHandle; 24 import android.service.notification.Condition; 25 import android.service.notification.IConditionProvider; 26 import android.service.notification.ZenModeConfig; 27 import android.service.notification.ZenModeConfig.ZenRule; 28 import android.util.ArrayMap; 29 import android.util.ArraySet; 30 import android.util.Log; 31 32 import com.android.internal.annotations.VisibleForTesting; 33 34 import java.io.PrintWriter; 35 36 /** 37 * Helper class for managing active rules from 38 * {@link android.service.notification.ConditionProviderService CPSes}. 39 */ 40 public class ZenModeConditions implements ConditionProviders.Callback { 41 private static final String TAG = ZenModeHelper.TAG; 42 private static final boolean DEBUG = ZenModeHelper.DEBUG; 43 44 private final ZenModeHelper mHelper; 45 private final ConditionProviders mConditionProviders; 46 47 @VisibleForTesting 48 protected final ArrayMap<Uri, ComponentName> mSubscriptions = new ArrayMap<>(); 49 ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders)50 public ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders) { 51 mHelper = helper; 52 mConditionProviders = conditionProviders; 53 if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.COUNTDOWN_PATH)) { 54 mConditionProviders.addSystemProvider(new CountdownConditionProvider()); 55 } 56 if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.SCHEDULE_PATH)) { 57 mConditionProviders.addSystemProvider(new ScheduleConditionProvider()); 58 } 59 if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) { 60 mConditionProviders.addSystemProvider(new EventConditionProvider()); 61 } 62 if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.CUSTOM_MANUAL_PATH)) { 63 mConditionProviders.addSystemProvider(new CustomManualConditionProvider()); 64 } 65 mConditionProviders.setCallback(this); 66 } 67 dump(PrintWriter pw, String prefix)68 public void dump(PrintWriter pw, String prefix) { 69 pw.print(prefix); pw.print("mSubscriptions="); pw.println(mSubscriptions); 70 } 71 evaluateConfig(ZenModeConfig config, ComponentName trigger, boolean processSubscriptions)72 public void evaluateConfig(ZenModeConfig config, ComponentName trigger, 73 boolean processSubscriptions) { 74 if (config == null) return; 75 if (!android.app.Flags.modesUi() && config.manualRule != null 76 && config.manualRule.condition != null 77 && !config.manualRule.isTrueOrUnknown()) { 78 if (DEBUG) Log.d(TAG, "evaluateConfig: clearing manual rule"); 79 config.manualRule = null; 80 } 81 final ArraySet<Uri> current = new ArraySet<>(); 82 evaluateRule(config.manualRule, current, null, processSubscriptions, true); 83 for (ZenRule automaticRule : config.automaticRules.values()) { 84 if (automaticRule.component != null) { 85 evaluateRule(automaticRule, current, trigger, processSubscriptions, false); 86 automaticRule.reconsiderConditionOverride(); 87 } 88 } 89 90 synchronized (mSubscriptions) { 91 final int N = mSubscriptions.size(); 92 for (int i = N - 1; i >= 0; i--) { 93 final Uri id = mSubscriptions.keyAt(i); 94 final ComponentName component = mSubscriptions.valueAt(i); 95 if (processSubscriptions) { 96 if (!current.contains(id)) { 97 mConditionProviders.unsubscribeIfNecessary(component, id); 98 mSubscriptions.removeAt(i); 99 } 100 } 101 } 102 } 103 } 104 105 @Override onServiceAdded(ComponentName component)106 public void onServiceAdded(ComponentName component) { 107 if (DEBUG) Log.d(TAG, "onServiceAdded " + component); 108 final int callingUid = Binder.getCallingUid(); 109 mHelper.setConfig(mHelper.getConfig(), component, 110 callingUid == Process.SYSTEM_UID ? ZenModeConfig.ORIGIN_SYSTEM 111 : ZenModeConfig.ORIGIN_APP, 112 "zmc.onServiceAdded:" + component, callingUid); 113 } 114 115 @Override onConditionChanged(Uri id, Condition condition, int callingUid)116 public void onConditionChanged(Uri id, Condition condition, int callingUid) { 117 if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition); 118 ZenModeConfig config = mHelper.getConfig(); 119 if (config == null) return; 120 if (!Flags.fixCallingUidFromCps()) { 121 // Old behavior: overwrite with known-bad callingUid (always system_server). 122 callingUid = Binder.getCallingUid(); 123 } 124 125 // This change is known to be for UserHandle.CURRENT because ConditionProviders for 126 // background users are not bound. 127 mHelper.setAutomaticZenRuleStateFromConditionProvider(UserHandle.CURRENT, id, condition, 128 callingUid == Process.SYSTEM_UID ? ZenModeConfig.ORIGIN_SYSTEM 129 : ZenModeConfig.ORIGIN_APP, 130 callingUid); 131 } 132 133 // Only valid for CPS backed rules evaluateRule(ZenRule rule, ArraySet<Uri> current, ComponentName trigger, boolean processSubscriptions, boolean isManual)134 private void evaluateRule(ZenRule rule, ArraySet<Uri> current, ComponentName trigger, 135 boolean processSubscriptions, boolean isManual) { 136 if (rule == null || rule.conditionId == null) return; 137 if (rule.configurationActivity != null) return; 138 final Uri id = rule.conditionId; 139 boolean isSystemCondition = false; 140 for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) { 141 if (sp.isValidConditionId(id)) { 142 mConditionProviders.ensureRecordExists(sp.getComponent(), id, sp.asInterface()); 143 rule.component = sp.getComponent(); 144 isSystemCondition = true; 145 } 146 } 147 // ensure that we have a record of the rule if it's backed by an currently alive CPS 148 if (!isSystemCondition) { 149 final IConditionProvider cp = mConditionProviders.findConditionProvider(rule.component); 150 if (DEBUG) Log.d(TAG, "Ensure external rule exists: " + (cp != null) + " for " + id); 151 if (cp != null) { 152 mConditionProviders.ensureRecordExists(rule.component, id, cp); 153 } 154 } 155 // empty rule? disable and bail early 156 if (rule.component == null && rule.enabler == null) { 157 if (!isManual) { 158 Log.w(TAG, "No component found for automatic rule: " + rule.conditionId); 159 rule.enabled = false; 160 } 161 return; 162 } 163 if (current != null) { 164 current.add(id); 165 } 166 167 // If the rule is bound by a CPS and the CPS is alive, tell them about the rule 168 if (processSubscriptions && ((trigger != null && trigger.equals(rule.component)) 169 || isSystemCondition)) { 170 if (DEBUG) Log.d(TAG, "Subscribing to " + rule.component); 171 if (mConditionProviders.subscribeIfNecessary(rule.component, rule.conditionId)) { 172 synchronized (mSubscriptions) { 173 mSubscriptions.put(rule.conditionId, rule.component); 174 } 175 } else { 176 rule.condition = null; 177 if (DEBUG) Log.d(TAG, "zmc failed to subscribe"); 178 } 179 } 180 // backfill the rule state from CPS backed components if it's missing 181 if (rule.component != null && rule.condition == null) { 182 rule.condition = mConditionProviders.findCondition(rule.component, rule.conditionId); 183 if (rule.condition != null && DEBUG) Log.d(TAG, "Found existing condition for: " 184 + rule.conditionId); 185 } 186 } 187 } 188