content: /*
   * Copyright (C) 2018 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.android.server.am;
  
  import android.content.ContentResolver;
  import android.database.ContentObserver;
  import android.os.Handler;
  import android.provider.Settings;
  import android.util.KeyValueListParser;
  import android.util.Slog;
  import android.util.TimeUtils;
  
  import java.io.PrintWriter;
  
  /**
   * Tunable parameters for broadcast dispatch policy
   */
  public class BroadcastConstants {
      private static final String TAG = "BroadcastConstants";
  
      // Value element names within the Settings record
      static final String KEY_TIMEOUT = "bcast_timeout";
      static final String KEY_SLOW_TIME = "bcast_slow_time";
      static final String KEY_DEFERRAL = "bcast_deferral";
      static final String KEY_DEFERRAL_DECAY_FACTOR = "bcast_deferral_decay_factor";
      static final String KEY_DEFERRAL_FLOOR = "bcast_deferral_floor";
      static final String KEY_ALLOW_BG_ACTIVITY_START_TIMEOUT =
              "bcast_allow_bg_activity_start_timeout";
  
      // All time intervals are in milliseconds
      private static final long DEFAULT_TIMEOUT = 10_000;
      private static final long DEFAULT_SLOW_TIME = 5_000;
      private static final long DEFAULT_DEFERRAL = 5_000;
      private static final float DEFAULT_DEFERRAL_DECAY_FACTOR = 0.75f;
      private static final long DEFAULT_DEFERRAL_FLOOR = 0;
      private static final long DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT = 10_000;
  
      // All time constants are in milliseconds
  
      // Timeout period for this broadcast queue
      public long TIMEOUT = DEFAULT_TIMEOUT;
      // Handling time above which we declare that a broadcast recipient was "slow".  Any
      // value <= zero is interpreted as disabling broadcast deferral policy entirely.
      public long SLOW_TIME = DEFAULT_SLOW_TIME;
      // How long to initially defer broadcasts, if an app is slow to handle one
      public long DEFERRAL = DEFAULT_DEFERRAL;
      // Decay factor for successive broadcasts' deferral time
      public float DEFERRAL_DECAY_FACTOR = DEFAULT_DEFERRAL_DECAY_FACTOR;
      // Minimum that the deferral time can decay to until the backlog fully clears
      public long DEFERRAL_FLOOR = DEFAULT_DEFERRAL_FLOOR;
      // For how long after a whitelisted receiver's start its process can start a background activity
      public long ALLOW_BG_ACTIVITY_START_TIMEOUT = DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT;
  
      // Settings override tracking for this instance
      private String mSettingsKey;
      private SettingsObserver mSettingsObserver;
      private ContentResolver mResolver;
      private final KeyValueListParser mParser = new KeyValueListParser(',');
  
      class SettingsObserver extends ContentObserver {
          SettingsObserver(Handler handler) {
              super(handler);
          }
  
          @Override
          public void onChange(boolean selfChange) {
              updateConstants();
          }
      }
  
      // A given constants instance is configured to observe specific keys from which
      // that instance's values are drawn.
      public BroadcastConstants(String settingsKey) {
          mSettingsKey = settingsKey;
      }
  
      /**
       * Spin up the observer lazily, since it can only happen once the settings provider
       * has been brought into service
       */
      public void startObserving(Handler handler, ContentResolver resolver) {
          mResolver = resolver;
  
          mSettingsObserver = new SettingsObserver(handler);
          mResolver.registerContentObserver(Settings.Global.getUriFor(mSettingsKey),
                  false, mSettingsObserver);
  
          updateConstants();
      }
  
      private void updateConstants() {
          synchronized (mParser) {
              try {
                  mParser.setString(Settings.Global.getString(mResolver, mSettingsKey));
              } catch (IllegalArgumentException e) {
                  Slog.e(TAG, "Bad broadcast settings in key '" + mSettingsKey + "'", e);
                  return;
              }
  
              // Unspecified fields retain their current value rather than revert to default
              TIMEOUT = mParser.getLong(KEY_TIMEOUT, TIMEOUT);
              SLOW_TIME = mParser.getLong(KEY_SLOW_TIME, SLOW_TIME);
              DEFERRAL = mParser.getLong(KEY_DEFERRAL, DEFERRAL);
              DEFERRAL_DECAY_FACTOR = mParser.getFloat(KEY_DEFERRAL_DECAY_FACTOR,
                      DEFERRAL_DECAY_FACTOR);
              DEFERRAL_FLOOR = mParser.getLong(KEY_DEFERRAL_FLOOR, DEFERRAL_FLOOR);
              ALLOW_BG_ACTIVITY_START_TIMEOUT = mParser.getLong(KEY_ALLOW_BG_ACTIVITY_START_TIMEOUT,
                      ALLOW_BG_ACTIVITY_START_TIMEOUT);
          }
      }
  
      /**
       * Standard dumpsys support; invoked from BroadcastQueue dump
       */
      public void dump(PrintWriter pw) {
          synchronized (mParser) {
              pw.println();
              pw.print("  Broadcast parameters (key=");
              pw.print(mSettingsKey);
              pw.print(", observing=");
              pw.print(mSettingsObserver != null);
              pw.println("):");
  
              pw.print("    "); pw.print(KEY_TIMEOUT); pw.print(" = ");
              TimeUtils.formatDuration(TIMEOUT, pw);
              pw.println();
  
              pw.print("    "); pw.print(KEY_SLOW_TIME); pw.print(" = ");
              TimeUtils.formatDuration(SLOW_TIME, pw);
              pw.println();
  
              pw.print("    "); pw.print(KEY_DEFERRAL); pw.print(" = ");
              TimeUtils.formatDuration(DEFERRAL, pw);
              pw.println();
  
              pw.print("    "); pw.print(KEY_DEFERRAL_DECAY_FACTOR); pw.print(" = ");
              pw.println(DEFERRAL_DECAY_FACTOR);
  
              pw.print("    "); pw.print(KEY_DEFERRAL_FLOOR); pw.print(" = ");
              TimeUtils.formatDuration(DEFERRAL_FLOOR, pw);
  
              pw.print("    "); pw.print(KEY_ALLOW_BG_ACTIVITY_START_TIMEOUT); pw.print(" = ");
              TimeUtils.formatDuration(ALLOW_BG_ACTIVITY_START_TIMEOUT, pw);
              pw.println();
          }
      }
  }
  