Merge "Track some event history and include it in netpolicy dump."
This commit is contained in:
committed by
Android (Google) Code Review
commit
9fdbc957c6
@@ -60,6 +60,25 @@ public class RingBuffer<T> {
|
||||
mBuffer[indexOf(mCursor++)] = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns object of type <T> at the next writable slot, creating one if it is not already
|
||||
* available. In case of any errors while creating the object, <code>null</code> will
|
||||
* be returned.
|
||||
*/
|
||||
public T getNextSlot() {
|
||||
final int nextSlotIdx = indexOf(mCursor++);
|
||||
T item = mBuffer[nextSlotIdx];
|
||||
if (item == null) {
|
||||
try {
|
||||
item = (T) mBuffer.getClass().getComponentType().newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
return null;
|
||||
}
|
||||
mBuffer[nextSlotIdx] = item;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public T[] toArray() {
|
||||
// Only generic way to create a T[] from another T[]
|
||||
T[] out = Arrays.copyOf(mBuffer, size(), (Class<T[]>) mBuffer.getClass());
|
||||
|
||||
@@ -40,7 +40,7 @@ import android.view.Display;
|
||||
/**
|
||||
* Activity manager code dealing with processes.
|
||||
*/
|
||||
final class ProcessList {
|
||||
public final class ProcessList {
|
||||
private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;
|
||||
|
||||
// The minimum time we allow between crashes, for us to consider this
|
||||
|
||||
@@ -0,0 +1,514 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.net;
|
||||
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
|
||||
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.net.NetworkPolicyManager;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.RingBuffer;
|
||||
import com.android.server.am.ProcessList;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
public class NetworkPolicyLogger {
|
||||
static final String TAG = "NetworkPolicy";
|
||||
|
||||
static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
|
||||
static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
private static final int MAX_LOG_SIZE =
|
||||
ActivityManager.isLowRamDeviceStatic() ? 20 : 50;
|
||||
private static final int MAX_NETWORK_BLOCKED_LOG_SIZE =
|
||||
ActivityManager.isLowRamDeviceStatic() ? 50 : 100;
|
||||
|
||||
private static final int EVENT_TYPE_GENERIC = 0;
|
||||
private static final int EVENT_NETWORK_BLOCKED = 1;
|
||||
private static final int EVENT_UID_STATE_CHANGED = 2;
|
||||
private static final int EVENT_POLICIES_CHANGED = 3;
|
||||
private static final int EVENT_METEREDNESS_CHANGED = 4;
|
||||
private static final int EVENT_USER_STATE_REMOVED = 5;
|
||||
private static final int EVENT_RESTRICT_BG_CHANGED = 6;
|
||||
private static final int EVENT_DEVICE_IDLE_MODE_ENABLED = 7;
|
||||
private static final int EVENT_APP_IDLE_STATE_CHANGED = 8;
|
||||
private static final int EVENT_PAROLE_STATE_CHANGED = 9;
|
||||
private static final int EVENT_TEMP_POWER_SAVE_WL_CHANGED = 10;
|
||||
private static final int EVENT_UID_FIREWALL_RULE_CHANGED = 11;
|
||||
private static final int EVENT_FIREWALL_CHAIN_ENABLED = 12;
|
||||
|
||||
static final int NTWK_BLOCKED_POWER = 0;
|
||||
static final int NTWK_ALLOWED_NON_METERED = 1;
|
||||
static final int NTWK_BLOCKED_BLACKLIST = 2;
|
||||
static final int NTWK_ALLOWED_WHITELIST = 3;
|
||||
static final int NTWK_ALLOWED_TMP_WHITELIST = 4;
|
||||
static final int NTWK_BLOCKED_BG_RESTRICT = 5;
|
||||
static final int NTWK_ALLOWED_DEFAULT = 6;
|
||||
|
||||
private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE);
|
||||
private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE);
|
||||
private final LogBuffer mEventsBuffer = new LogBuffer(MAX_LOG_SIZE);
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
void networkBlocked(int uid, int reason) {
|
||||
synchronized (mLock) {
|
||||
if (LOGD) Slog.d(TAG, uid + " is " + getBlockedReason(reason));
|
||||
mNetworkBlockedBuffer.networkBlocked(uid, reason);
|
||||
}
|
||||
}
|
||||
|
||||
void uidStateChanged(int uid, int procState, long procStateSeq) {
|
||||
synchronized (mLock) {
|
||||
if (LOGV) Slog.v(TAG,
|
||||
uid + " state changed to " + procState + " with seq=" + procStateSeq);
|
||||
mUidStateChangeBuffer.uidStateChanged(uid, procState, procStateSeq);
|
||||
}
|
||||
}
|
||||
|
||||
void event(String msg) {
|
||||
synchronized (mLock) {
|
||||
if (LOGV) Slog.v(TAG, msg);
|
||||
mEventsBuffer.event(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void uidPolicyChanged(int uid, int oldPolicy, int newPolicy) {
|
||||
synchronized (mLock) {
|
||||
if (LOGV) Slog.v(TAG, getPolicyChangedLog(uid, oldPolicy, newPolicy));
|
||||
mEventsBuffer.uidPolicyChanged(uid, oldPolicy, newPolicy);
|
||||
}
|
||||
}
|
||||
|
||||
void meterednessChanged(int netId, boolean newMetered) {
|
||||
synchronized (mLock) {
|
||||
if (LOGD) Slog.d(TAG, getMeterednessChangedLog(netId, newMetered));
|
||||
mEventsBuffer.meterednessChanged(netId, newMetered);
|
||||
}
|
||||
}
|
||||
|
||||
void removingUserState(int userId) {
|
||||
synchronized (mLock) {
|
||||
if (LOGD) Slog.d(TAG, getUserRemovedLog(userId));
|
||||
mEventsBuffer.userRemoved(userId);
|
||||
}
|
||||
}
|
||||
|
||||
void restrictBackgroundChanged(boolean oldValue, boolean newValue) {
|
||||
synchronized (mLock) {
|
||||
if (LOGD) Slog.d(TAG,
|
||||
getRestrictBackgroundChangedLog(oldValue, newValue));
|
||||
mEventsBuffer.restrictBackgroundChanged(oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
void deviceIdleModeEnabled(boolean enabled) {
|
||||
synchronized (mLock) {
|
||||
if (LOGD) Slog.d(TAG, getDeviceIdleModeEnabled(enabled));
|
||||
mEventsBuffer.deviceIdleModeEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void appIdleStateChanged(int uid, boolean idle) {
|
||||
synchronized (mLock) {
|
||||
if (LOGD) Slog.d(TAG, getAppIdleChangedLog(uid, idle));
|
||||
mEventsBuffer.appIdleStateChanged(uid, idle);
|
||||
}
|
||||
}
|
||||
|
||||
void paroleStateChanged(boolean paroleOn) {
|
||||
synchronized (mLock) {
|
||||
if (LOGD) Slog.d(TAG, getParoleStateChanged(paroleOn));
|
||||
mEventsBuffer.paroleStateChanged(paroleOn);
|
||||
}
|
||||
}
|
||||
|
||||
void tempPowerSaveWlChanged(int appId, boolean added) {
|
||||
synchronized (mLock) {
|
||||
if (LOGV) Slog.v(TAG, getTempPowerSaveWlChangedLog(appId, added));
|
||||
mEventsBuffer.tempPowerSaveWlChanged(appId, added);
|
||||
}
|
||||
}
|
||||
|
||||
void uidFirewallRuleChanged(int chain, int uid, int rule) {
|
||||
synchronized (mLock) {
|
||||
if (LOGV) Slog.v(TAG, getUidFirewallRuleChangedLog(chain, uid, rule));
|
||||
mEventsBuffer.uidFirewallRuleChanged(chain, uid, rule);
|
||||
}
|
||||
}
|
||||
|
||||
void firewallChainEnabled(int chain, boolean enabled) {
|
||||
synchronized (mLock) {
|
||||
if (LOGD) Slog.d(TAG, getFirewallChainEnabledLog(chain, enabled));
|
||||
mEventsBuffer.firewallChainEnabled(chain, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void firewallRulesChanged(int chain, int[] uids, int[] rules) {
|
||||
synchronized (mLock) {
|
||||
final String log = "Firewall rules changed for " + getFirewallChainName(chain)
|
||||
+ "; uids=" + Arrays.toString(uids) + "; rules=" + Arrays.toString(rules);
|
||||
if (LOGD) Slog.d(TAG, log);
|
||||
mEventsBuffer.event(log);
|
||||
}
|
||||
}
|
||||
|
||||
void dumpLogs(IndentingPrintWriter pw) {
|
||||
synchronized (mLock) {
|
||||
pw.println();
|
||||
pw.println("mEventLogs (most recent first):");
|
||||
pw.increaseIndent();
|
||||
mEventsBuffer.reverseDump(pw);
|
||||
pw.decreaseIndent();
|
||||
|
||||
pw.println();
|
||||
pw.println("mNetworkBlockedLogs (most recent first):");
|
||||
pw.increaseIndent();
|
||||
mNetworkBlockedBuffer.reverseDump(pw);
|
||||
pw.decreaseIndent();
|
||||
|
||||
pw.println();
|
||||
pw.println("mUidStateChangeLogs (most recent first):");
|
||||
pw.increaseIndent();
|
||||
mUidStateChangeBuffer.reverseDump(pw);
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getBlockedReason(int reason) {
|
||||
switch (reason) {
|
||||
case NTWK_BLOCKED_POWER:
|
||||
return "blocked by power restrictions";
|
||||
case NTWK_ALLOWED_NON_METERED:
|
||||
return "allowed on unmetered network";
|
||||
case NTWK_BLOCKED_BLACKLIST:
|
||||
return "blacklisted on metered network";
|
||||
case NTWK_ALLOWED_WHITELIST:
|
||||
return "whitelisted on metered network";
|
||||
case NTWK_ALLOWED_TMP_WHITELIST:
|
||||
return "temporary whitelisted on metered network";
|
||||
case NTWK_BLOCKED_BG_RESTRICT:
|
||||
return "blocked when background is restricted";
|
||||
case NTWK_ALLOWED_DEFAULT:
|
||||
return "allowed by default";
|
||||
default:
|
||||
return String.valueOf(reason);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getPolicyChangedLog(int uid, int oldPolicy, int newPolicy) {
|
||||
return "Policy for " + uid + " changed from "
|
||||
+ NetworkPolicyManager.uidPoliciesToString(oldPolicy) + " to "
|
||||
+ NetworkPolicyManager.uidPoliciesToString(newPolicy);
|
||||
}
|
||||
|
||||
private static String getMeterednessChangedLog(int netId, boolean newMetered) {
|
||||
return "Meteredness of netId=" + netId + " changed to " + newMetered;
|
||||
}
|
||||
|
||||
private static String getUserRemovedLog(int userId) {
|
||||
return "Remove state for u" + userId;
|
||||
}
|
||||
|
||||
private static String getRestrictBackgroundChangedLog(boolean oldValue, boolean newValue) {
|
||||
return "Changed restrictBackground: " + oldValue + "->" + newValue;
|
||||
}
|
||||
|
||||
private static String getDeviceIdleModeEnabled(boolean enabled) {
|
||||
return "DeviceIdleMode enabled: " + enabled;
|
||||
}
|
||||
|
||||
private static String getAppIdleChangedLog(int uid, boolean idle) {
|
||||
return "App idle state of uid " + uid + ": " + idle;
|
||||
}
|
||||
|
||||
private static String getParoleStateChanged(boolean paroleOn) {
|
||||
return "Parole state: " + paroleOn;
|
||||
}
|
||||
|
||||
private static String getTempPowerSaveWlChangedLog(int appId, boolean added) {
|
||||
return "temp-power-save whitelist for " + appId + " changed to: " + added;
|
||||
}
|
||||
|
||||
private static String getUidFirewallRuleChangedLog(int chain, int uid, int rule) {
|
||||
return String.format("Firewall rule changed: %d-%s-%s",
|
||||
uid, getFirewallChainName(chain), getFirewallRuleName(rule));
|
||||
}
|
||||
|
||||
private static String getFirewallChainEnabledLog(int chain, boolean enabled) {
|
||||
return "Firewall chain " + getFirewallChainName(chain) + " state: " + enabled;
|
||||
}
|
||||
|
||||
private static String getFirewallChainName(int chain) {
|
||||
switch (chain) {
|
||||
case FIREWALL_CHAIN_DOZABLE:
|
||||
return FIREWALL_CHAIN_NAME_DOZABLE;
|
||||
case FIREWALL_CHAIN_STANDBY:
|
||||
return FIREWALL_CHAIN_NAME_STANDBY;
|
||||
case FIREWALL_CHAIN_POWERSAVE:
|
||||
return FIREWALL_CHAIN_NAME_POWERSAVE;
|
||||
default:
|
||||
return String.valueOf(chain);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getFirewallRuleName(int rule) {
|
||||
switch (rule) {
|
||||
case FIREWALL_RULE_DEFAULT:
|
||||
return "default";
|
||||
case FIREWALL_RULE_ALLOW:
|
||||
return "allow";
|
||||
case FIREWALL_RULE_DENY:
|
||||
return "deny";
|
||||
default:
|
||||
return String.valueOf(rule);
|
||||
}
|
||||
}
|
||||
|
||||
private final static class LogBuffer extends RingBuffer<Data> {
|
||||
private static final SimpleDateFormat sFormatter
|
||||
= new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss:SSS");
|
||||
private static final Date sDate = new Date();
|
||||
|
||||
public LogBuffer(int capacity) {
|
||||
super(Data.class, capacity);
|
||||
}
|
||||
|
||||
public void uidStateChanged(int uid, int procState, long procStateSeq) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_UID_STATE_CHANGED;
|
||||
data.ifield1 = uid;
|
||||
data.ifield2 = procState;
|
||||
data.lfield1 = procStateSeq;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void event(String msg) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_TYPE_GENERIC;
|
||||
data.sfield1 = msg;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void networkBlocked(int uid, int reason) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_NETWORK_BLOCKED;
|
||||
data.ifield1 = uid;
|
||||
data.ifield2 = reason;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void uidPolicyChanged(int uid, int oldPolicy, int newPolicy) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_POLICIES_CHANGED;
|
||||
data.ifield1 = uid;
|
||||
data.ifield2 = oldPolicy;
|
||||
data.ifield3 = newPolicy;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void meterednessChanged(int netId, boolean newMetered) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_METEREDNESS_CHANGED;
|
||||
data.ifield1 = netId;
|
||||
data.bfield1 = newMetered;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void userRemoved(int userId) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_USER_STATE_REMOVED;
|
||||
data.ifield1 = userId;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void restrictBackgroundChanged(boolean oldValue, boolean newValue) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_RESTRICT_BG_CHANGED;
|
||||
data.bfield1 = oldValue;
|
||||
data.bfield2 = newValue;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void deviceIdleModeEnabled(boolean enabled) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_DEVICE_IDLE_MODE_ENABLED;
|
||||
data.bfield1 = enabled;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void appIdleStateChanged(int uid, boolean idle) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_APP_IDLE_STATE_CHANGED;
|
||||
data.ifield1 = uid;
|
||||
data.bfield1 = idle;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void paroleStateChanged(boolean paroleOn) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_PAROLE_STATE_CHANGED;
|
||||
data.bfield1 = paroleOn;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void tempPowerSaveWlChanged(int appId, boolean added) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_TEMP_POWER_SAVE_WL_CHANGED;
|
||||
data.ifield1 = appId;
|
||||
data.bfield1 = added;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void uidFirewallRuleChanged(int chain, int uid, int rule) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_UID_FIREWALL_RULE_CHANGED;
|
||||
data.ifield1 = chain;
|
||||
data.ifield2 = uid;
|
||||
data.ifield3 = rule;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void firewallChainEnabled(int chain, boolean enabled) {
|
||||
final Data data = getNextSlot();
|
||||
if (data == null) return;
|
||||
|
||||
data.reset();
|
||||
data.type = EVENT_FIREWALL_CHAIN_ENABLED;
|
||||
data.ifield1 = chain;
|
||||
data.bfield1 = enabled;
|
||||
data.timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void reverseDump(IndentingPrintWriter pw) {
|
||||
final Data[] allData = toArray();
|
||||
for (int i = allData.length - 1; i >= 0; --i) {
|
||||
if (allData[i] == null) {
|
||||
pw.println("NULL");
|
||||
continue;
|
||||
}
|
||||
pw.print(formatDate(allData[i].timeStamp));
|
||||
pw.print(" - ");
|
||||
pw.println(getContent(allData[i]));
|
||||
}
|
||||
}
|
||||
|
||||
public String getContent(Data data) {
|
||||
switch (data.type) {
|
||||
case EVENT_TYPE_GENERIC:
|
||||
return data.sfield1;
|
||||
case EVENT_NETWORK_BLOCKED:
|
||||
return data.ifield1 + "-" + getBlockedReason(data.ifield2);
|
||||
case EVENT_UID_STATE_CHANGED:
|
||||
return data.ifield1 + "-" + ProcessList.makeProcStateString(data.ifield2)
|
||||
+ "-" + data.lfield1;
|
||||
case EVENT_POLICIES_CHANGED:
|
||||
return getPolicyChangedLog(data.ifield1, data.ifield2, data.ifield3);
|
||||
case EVENT_METEREDNESS_CHANGED:
|
||||
return getMeterednessChangedLog(data.ifield1, data.bfield1);
|
||||
case EVENT_USER_STATE_REMOVED:
|
||||
return getUserRemovedLog(data.ifield1);
|
||||
case EVENT_RESTRICT_BG_CHANGED:
|
||||
return getRestrictBackgroundChangedLog(data.bfield1, data.bfield2);
|
||||
case EVENT_DEVICE_IDLE_MODE_ENABLED:
|
||||
return getDeviceIdleModeEnabled(data.bfield1);
|
||||
case EVENT_APP_IDLE_STATE_CHANGED:
|
||||
return getAppIdleChangedLog(data.ifield1, data.bfield1);
|
||||
case EVENT_PAROLE_STATE_CHANGED:
|
||||
return getParoleStateChanged(data.bfield1);
|
||||
case EVENT_TEMP_POWER_SAVE_WL_CHANGED:
|
||||
return getTempPowerSaveWlChangedLog(data.ifield1, data.bfield1);
|
||||
case EVENT_UID_FIREWALL_RULE_CHANGED:
|
||||
return getUidFirewallRuleChangedLog(data.ifield1, data.ifield2, data.ifield3);
|
||||
case EVENT_FIREWALL_CHAIN_ENABLED:
|
||||
return getFirewallChainEnabledLog(data.ifield1, data.bfield1);
|
||||
default:
|
||||
return String.valueOf(data.type);
|
||||
}
|
||||
}
|
||||
|
||||
private String formatDate(long millis) {
|
||||
sDate.setTime(millis);
|
||||
return sFormatter.format(sDate);
|
||||
}
|
||||
}
|
||||
|
||||
public final static class Data {
|
||||
int type;
|
||||
long timeStamp;
|
||||
|
||||
int ifield1;
|
||||
int ifield2;
|
||||
int ifield3;
|
||||
long lfield1;
|
||||
boolean bfield1;
|
||||
boolean bfield2;
|
||||
String sfield1;
|
||||
|
||||
public void reset(){
|
||||
sfield1 = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,13 @@ import static com.android.internal.util.XmlUtils.writeIntAttribute;
|
||||
import static com.android.internal.util.XmlUtils.writeLongAttribute;
|
||||
import static com.android.internal.util.XmlUtils.writeStringAttribute;
|
||||
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
|
||||
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_DEFAULT;
|
||||
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_NON_METERED;
|
||||
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_TMP_WHITELIST;
|
||||
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_WHITELIST;
|
||||
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BG_RESTRICT;
|
||||
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BLACKLIST;
|
||||
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_POWER;
|
||||
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
|
||||
|
||||
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
|
||||
@@ -248,9 +255,9 @@ import java.util.concurrent.TimeUnit;
|
||||
* </ul>
|
||||
*/
|
||||
public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
static final String TAG = "NetworkPolicy";
|
||||
private static final boolean LOGD = false;
|
||||
private static final boolean LOGV = false;
|
||||
static final String TAG = NetworkPolicyLogger.TAG;
|
||||
private static final boolean LOGD = NetworkPolicyLogger.LOGD;
|
||||
private static final boolean LOGV = NetworkPolicyLogger.LOGV;
|
||||
|
||||
private static final int VERSION_INIT = 1;
|
||||
private static final int VERSION_ADDED_SNOOZE = 2;
|
||||
@@ -265,13 +272,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
private static final int VERSION_ADDED_CYCLE = 11;
|
||||
private static final int VERSION_LATEST = VERSION_ADDED_CYCLE;
|
||||
|
||||
/**
|
||||
* Max items written to {@link #ProcStateSeqHistory}.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static final int MAX_PROC_STATE_SEQ_HISTORY =
|
||||
ActivityManager.isLowRamDeviceStatic() ? 50 : 200;
|
||||
|
||||
@VisibleForTesting
|
||||
public static final int TYPE_WARNING = SystemMessage.NOTE_NET_WARNING;
|
||||
@VisibleForTesting
|
||||
@@ -471,13 +471,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
|
||||
private ActivityManagerInternal mActivityManagerInternal;
|
||||
|
||||
/**
|
||||
* This is used for debugging purposes. Whenever the IUidObserver.onUidStateChanged is called,
|
||||
* the uid and procStateSeq will be written to this and will be printed as part of dump.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public ProcStateSeqHistory mObservedHistory
|
||||
= new ProcStateSeqHistory(MAX_PROC_STATE_SEQ_HISTORY);
|
||||
private final NetworkPolicyLogger mLogger = new NetworkPolicyLogger();
|
||||
|
||||
// TODO: keep whitelist of system-critical services that should never have
|
||||
// rules enforced, such as system, phone, and radio UIDs.
|
||||
@@ -966,6 +960,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
|
||||
|
||||
if ((oldMetered != newMetered) || mNetworkMetered.indexOfKey(network.netId) < 0) {
|
||||
mLogger.meterednessChanged(network.netId, newMetered);
|
||||
mNetworkMetered.put(network.netId, newMetered);
|
||||
updateNetworkRulesNL();
|
||||
}
|
||||
@@ -2148,6 +2143,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
|
||||
if (oldPolicy != policy) {
|
||||
setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
|
||||
mLogger.uidPolicyChanged(uid, oldPolicy, policy);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
@@ -2168,6 +2164,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
policy |= oldPolicy;
|
||||
if (oldPolicy != policy) {
|
||||
setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
|
||||
mLogger.uidPolicyChanged(uid, oldPolicy, policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2185,6 +2182,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
policy = oldPolicy & ~policy;
|
||||
if (oldPolicy != policy) {
|
||||
setUidPolicyUncheckedUL(uid, oldPolicy, policy, true);
|
||||
mLogger.uidPolicyChanged(uid, oldPolicy, policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2264,7 +2262,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
*/
|
||||
boolean removeUserStateUL(int userId, boolean writePolicy) {
|
||||
|
||||
if (LOGV) Slog.v(TAG, "removeUserStateUL()");
|
||||
mLogger.removingUserState(userId);
|
||||
boolean changed = false;
|
||||
|
||||
// Remove entries from revoked default restricted background UID whitelist
|
||||
@@ -2429,7 +2427,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
@Override
|
||||
public void onTetheringChanged(String iface, boolean tethering) {
|
||||
// No need to enforce permission because setRestrictBackground() will do it.
|
||||
if (LOGD) Log.d(TAG, "onTetherStateChanged(" + iface + ", " + tethering + ")");
|
||||
synchronized (mUidRulesFirstLock) {
|
||||
if (mRestrictBackground && tethering) {
|
||||
Log.d(TAG, "Tethering on (" + iface +"); disable Data Saver");
|
||||
@@ -2486,6 +2483,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
|
||||
sendRestrictBackgroundChangedMsg();
|
||||
mLogger.restrictBackgroundChanged(oldRestrictBackground, mRestrictBackground);
|
||||
|
||||
if (mRestrictBackgroundPowerState.globalBatterySaverEnabled) {
|
||||
mRestrictBackgroundChangedInBsm = true;
|
||||
@@ -2551,6 +2549,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
return;
|
||||
}
|
||||
mDeviceIdleMode = enabled;
|
||||
mLogger.deviceIdleModeEnabled(enabled);
|
||||
if (mSystemReady) {
|
||||
// Device idle change means we need to rebuild rules for all
|
||||
// known apps, so do a global refresh.
|
||||
@@ -2964,10 +2963,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
fout.decreaseIndent();
|
||||
|
||||
fout.println("Observed uid state changes:");
|
||||
fout.increaseIndent();
|
||||
mObservedHistory.dumpUL(fout);
|
||||
fout.decreaseIndent();
|
||||
mLogger.dumpLogs(fout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3750,8 +3746,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
try {
|
||||
final int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
|
||||
if (LOGV) Log.v(TAG, "onAppIdleStateChanged(): uid=" + uid + ", idle=" + idle);
|
||||
synchronized (mUidRulesFirstLock) {
|
||||
mLogger.appIdleStateChanged(uid, idle);
|
||||
updateRuleForAppIdleUL(uid);
|
||||
updateRulesForPowerRestrictionsUL(uid);
|
||||
}
|
||||
@@ -3762,6 +3758,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
@Override
|
||||
public void onParoleStateChanged(boolean isParoleOn) {
|
||||
synchronized (mUidRulesFirstLock) {
|
||||
mLogger.paroleStateChanged(isParoleOn);
|
||||
updateRulesForAppIdleParoleUL();
|
||||
}
|
||||
}
|
||||
@@ -3947,7 +3944,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
synchronized (mUidRulesFirstLock) {
|
||||
// We received a uid state change callback, add it to the history so that it
|
||||
// will be useful for debugging.
|
||||
mObservedHistory.addProcStateSeqUL(uid, procStateSeq);
|
||||
mLogger.uidStateChanged(uid, procState, procStateSeq);
|
||||
// Now update the network policy rules as per the updated uid state.
|
||||
updateUidStateUL(uid, procState);
|
||||
// Updating the network rules is done, so notify AMS about this.
|
||||
@@ -4081,6 +4078,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
rules[index] = uidRules.valueAt(index);
|
||||
}
|
||||
mNetworkManager.setFirewallUidRules(chain, uids, rules);
|
||||
mLogger.firewallRulesChanged(chain, uids, rules);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.wtf(TAG, "problem setting firewall uid rules", e);
|
||||
} catch (RemoteException e) {
|
||||
@@ -4107,6 +4105,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
|
||||
try {
|
||||
mNetworkManager.setFirewallUidRule(chain, uid, rule);
|
||||
mLogger.uidFirewallRuleChanged(chain, uid, rule);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.wtf(TAG, "problem setting firewall uid rules", e);
|
||||
} catch (RemoteException e) {
|
||||
@@ -4129,6 +4128,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
mFirewallChainStates.put(chain, enable);
|
||||
try {
|
||||
mNetworkManager.setFirewallChainEnabled(chain, enable);
|
||||
mLogger.firewallChainEnabled(chain, enable);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.wtf(TAG, "problem enable firewall chain", e);
|
||||
} catch (RemoteException e) {
|
||||
@@ -4305,30 +4305,30 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
isBackgroundRestricted = mRestrictBackground;
|
||||
}
|
||||
if (hasRule(uidRules, RULE_REJECT_ALL)) {
|
||||
if (LOGV) logUidStatus(uid, "blocked by power restrictions");
|
||||
mLogger.networkBlocked(uid, NTWK_BLOCKED_POWER);
|
||||
return true;
|
||||
}
|
||||
if (!isNetworkMetered) {
|
||||
if (LOGV) logUidStatus(uid, "allowed on unmetered network");
|
||||
mLogger.networkBlocked(uid, NTWK_ALLOWED_NON_METERED);
|
||||
return false;
|
||||
}
|
||||
if (hasRule(uidRules, RULE_REJECT_METERED)) {
|
||||
if (LOGV) logUidStatus(uid, "blacklisted on metered network");
|
||||
mLogger.networkBlocked(uid, NTWK_BLOCKED_BLACKLIST);
|
||||
return true;
|
||||
}
|
||||
if (hasRule(uidRules, RULE_ALLOW_METERED)) {
|
||||
if (LOGV) logUidStatus(uid, "whitelisted on metered network");
|
||||
mLogger.networkBlocked(uid, NTWK_ALLOWED_WHITELIST);
|
||||
return false;
|
||||
}
|
||||
if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
|
||||
if (LOGV) logUidStatus(uid, "temporary whitelisted on metered network");
|
||||
mLogger.networkBlocked(uid, NTWK_ALLOWED_TMP_WHITELIST);
|
||||
return false;
|
||||
}
|
||||
if (isBackgroundRestricted) {
|
||||
if (LOGV) logUidStatus(uid, "blocked when background is restricted");
|
||||
mLogger.networkBlocked(uid, NTWK_BLOCKED_BG_RESTRICT);
|
||||
return true;
|
||||
}
|
||||
if (LOGV) logUidStatus(uid, "allowed by default");
|
||||
mLogger.networkBlocked(uid, NTWK_ALLOWED_DEFAULT);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4379,6 +4379,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
@Override
|
||||
public void onTempPowerSaveWhitelistChange(int appId, boolean added) {
|
||||
synchronized (mUidRulesFirstLock) {
|
||||
mLogger.tempPowerSaveWlChanged(appId, added);
|
||||
if (added) {
|
||||
mPowerSaveTempWhitelistAppIds.put(appId, true);
|
||||
} else {
|
||||
@@ -4393,80 +4394,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
return (uidRules & rule) != 0;
|
||||
}
|
||||
|
||||
private static void logUidStatus(int uid, String descr) {
|
||||
Slog.d(TAG, String.format("uid %d is %s", uid, descr));
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is used for storing and dumping the last {@link #MAX_PROC_STATE_SEQ_HISTORY}
|
||||
* (uid, procStateSeq) pairs.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static final class ProcStateSeqHistory {
|
||||
private static final int INVALID_UID = -1;
|
||||
|
||||
/**
|
||||
* Denotes maximum number of items this history can hold.
|
||||
*/
|
||||
private final int mMaxCapacity;
|
||||
/**
|
||||
* Used for storing the uid information.
|
||||
*/
|
||||
private final int[] mUids;
|
||||
/**
|
||||
* Used for storing the sequence numbers associated with {@link #mUids}.
|
||||
*/
|
||||
private final long[] mProcStateSeqs;
|
||||
/**
|
||||
* Points to the next available slot for writing (uid, procStateSeq) pair.
|
||||
*/
|
||||
private int mHistoryNext;
|
||||
|
||||
public ProcStateSeqHistory(int maxCapacity) {
|
||||
mMaxCapacity = maxCapacity;
|
||||
mUids = new int[mMaxCapacity];
|
||||
Arrays.fill(mUids, INVALID_UID);
|
||||
mProcStateSeqs = new long[mMaxCapacity];
|
||||
}
|
||||
|
||||
@GuardedBy("mUidRulesFirstLock")
|
||||
public void addProcStateSeqUL(int uid, long procStateSeq) {
|
||||
mUids[mHistoryNext] = uid;
|
||||
mProcStateSeqs[mHistoryNext] = procStateSeq;
|
||||
mHistoryNext = increaseNext(mHistoryNext, 1);
|
||||
}
|
||||
|
||||
@GuardedBy("mUidRulesFirstLock")
|
||||
public void dumpUL(IndentingPrintWriter fout) {
|
||||
if (mUids[0] == INVALID_UID) {
|
||||
fout.println("NONE");
|
||||
return;
|
||||
}
|
||||
int index = mHistoryNext;
|
||||
do {
|
||||
index = increaseNext(index, -1);
|
||||
if (mUids[index] == INVALID_UID) {
|
||||
break;
|
||||
}
|
||||
fout.println(getString(mUids[index], mProcStateSeqs[index]));
|
||||
} while (index != mHistoryNext);
|
||||
}
|
||||
|
||||
public static String getString(int uid, long procStateSeq) {
|
||||
return "UID=" + uid + " Seq=" + procStateSeq;
|
||||
}
|
||||
|
||||
private int increaseNext(int next, int increment) {
|
||||
next += increment;
|
||||
if (next >= mMaxCapacity) {
|
||||
next = 0;
|
||||
} else if (next < 0) {
|
||||
next = mMaxCapacity - 1;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
}
|
||||
|
||||
private class NotificationId {
|
||||
private final String mTag;
|
||||
private final int mId;
|
||||
|
||||
@@ -37,7 +37,6 @@ import static android.telephony.CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_
|
||||
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
||||
import static android.text.format.Time.TIMEZONE_UTC;
|
||||
|
||||
import static com.android.server.net.NetworkPolicyManagerService.MAX_PROC_STATE_SEQ_HISTORY;
|
||||
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
|
||||
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
|
||||
import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
|
||||
@@ -61,7 +60,6 @@ import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -116,12 +114,10 @@ import android.util.RecurrenceRule;
|
||||
import android.util.TrustedTime;
|
||||
|
||||
import com.android.internal.telephony.PhoneConstants;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.test.BroadcastInterceptingContext;
|
||||
import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent;
|
||||
import com.android.server.net.NetworkPolicyManagerInternal;
|
||||
import com.android.server.net.NetworkPolicyManagerService;
|
||||
import com.android.server.net.NetworkPolicyManagerService.ProcStateSeqHistory;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
import libcore.io.Streams;
|
||||
@@ -142,12 +138,10 @@ import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -191,8 +185,6 @@ public class NetworkPolicyManagerServiceTest {
|
||||
private static final String TEST_IFACE = "test0";
|
||||
private static final String TEST_SSID = "AndroidAP";
|
||||
|
||||
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||
|
||||
private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi(TEST_SSID);
|
||||
|
||||
/**
|
||||
@@ -1109,14 +1101,6 @@ public class NetworkPolicyManagerServiceTest {
|
||||
final long procStateSeq = 222;
|
||||
callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq);
|
||||
verify(mActivityManagerInternal).notifyNetworkPolicyRulesUpdated(UID_A, procStateSeq);
|
||||
|
||||
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
final IndentingPrintWriter writer = new IndentingPrintWriter(
|
||||
new PrintWriter(outputStream), " ");
|
||||
mService.mObservedHistory.dumpUL(writer);
|
||||
writer.flush();
|
||||
assertEquals(ProcStateSeqHistory.getString(UID_A, procStateSeq),
|
||||
outputStream.toString().trim());
|
||||
}
|
||||
|
||||
private void callOnUidStateChanged(int uid, int procState, long procStateSeq)
|
||||
@@ -1129,59 +1113,6 @@ public class NetworkPolicyManagerServiceTest {
|
||||
latch.await(2, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcStateHistory() {
|
||||
// Verify dump works correctly with no elements added.
|
||||
verifyProcStateHistoryDump(0);
|
||||
|
||||
// Add items upto half of the max capacity and verify that dump works correctly.
|
||||
verifyProcStateHistoryDump(MAX_PROC_STATE_SEQ_HISTORY / 2);
|
||||
|
||||
// Add items upto the max capacity and verify that dump works correctly.
|
||||
verifyProcStateHistoryDump(MAX_PROC_STATE_SEQ_HISTORY);
|
||||
|
||||
// Add more items than max capacity and verify that dump works correctly.
|
||||
verifyProcStateHistoryDump(MAX_PROC_STATE_SEQ_HISTORY + MAX_PROC_STATE_SEQ_HISTORY / 2);
|
||||
|
||||
}
|
||||
|
||||
private void verifyProcStateHistoryDump(int count) {
|
||||
final ProcStateSeqHistory history = new ProcStateSeqHistory(MAX_PROC_STATE_SEQ_HISTORY);
|
||||
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
final IndentingPrintWriter writer = new IndentingPrintWriter(
|
||||
new PrintWriter(outputStream), " ");
|
||||
|
||||
if (count == 0) {
|
||||
// Verify with no uid info written to history.
|
||||
history.dumpUL(writer);
|
||||
writer.flush();
|
||||
assertEquals("When no uid info is there, dump should contain NONE",
|
||||
"NONE", outputStream.toString().trim());
|
||||
return;
|
||||
}
|
||||
|
||||
int uid = 111;
|
||||
long procStateSeq = 222;
|
||||
// Add count items and verify dump works correctly.
|
||||
for (int i = 0; i < count; ++i) {
|
||||
uid++;
|
||||
procStateSeq++;
|
||||
history.addProcStateSeqUL(uid, procStateSeq);
|
||||
}
|
||||
history.dumpUL(writer);
|
||||
writer.flush();
|
||||
final String[] uidsDump = outputStream.toString().split(LINE_SEPARATOR);
|
||||
// Dump will have at most MAX_PROC_STATE_SEQ_HISTORY items.
|
||||
final int expectedCount = (count < MAX_PROC_STATE_SEQ_HISTORY)
|
||||
? count : MAX_PROC_STATE_SEQ_HISTORY;
|
||||
assertEquals(expectedCount, uidsDump.length);
|
||||
for (int i = 0; i < expectedCount; ++i) {
|
||||
assertEquals(ProcStateSeqHistory.getString(uid, procStateSeq), uidsDump[i]);
|
||||
uid--;
|
||||
procStateSeq--;
|
||||
}
|
||||
}
|
||||
|
||||
private void assertCycleDayAsExpected(PersistableBundle config, int carrierCycleDay,
|
||||
boolean expectValid) {
|
||||
config.putInt(KEY_MONTHLY_DATA_CYCLE_DAY_INT, carrierCycleDay);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.internal.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.support.test.filters.SmallTest;
|
||||
@@ -129,6 +130,55 @@ public class RingBufferTest {
|
||||
assertArraysEqual(expected2, buffer.toArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNextSlot() {
|
||||
int capacity = 100;
|
||||
RingBuffer<DummyClass1> buffer = new RingBuffer<>(DummyClass1.class, capacity);
|
||||
|
||||
final DummyClass1[] actual = new DummyClass1[capacity];
|
||||
final DummyClass1[] expected = new DummyClass1[capacity];
|
||||
for (int i = 0; i < capacity; ++i) {
|
||||
final DummyClass1 obj = buffer.getNextSlot();
|
||||
obj.x = capacity * i;
|
||||
actual[i] = obj;
|
||||
expected[i] = new DummyClass1();
|
||||
expected[i].x = capacity * i;
|
||||
}
|
||||
assertArraysEqual(expected, buffer.toArray());
|
||||
|
||||
for (int i = 0; i < capacity; ++i) {
|
||||
if (actual[i] != buffer.getNextSlot()) {
|
||||
fail("getNextSlot() should re-use objects if available");
|
||||
}
|
||||
}
|
||||
|
||||
RingBuffer<DummyClass2> buffer2 = new RingBuffer<>(DummyClass2.class, capacity);
|
||||
assertNull("getNextSlot() should return null if the object can't be initiated "
|
||||
+ "(No nullary constructor)", buffer2.getNextSlot());
|
||||
|
||||
RingBuffer<DummyClass3> buffer3 = new RingBuffer<>(DummyClass3.class, capacity);
|
||||
assertNull("getNextSlot() should return null if the object can't be initiated "
|
||||
+ "(Inaccessible class)", buffer3.getNextSlot());
|
||||
}
|
||||
|
||||
public static final class DummyClass1 {
|
||||
int x;
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof DummyClass1) {
|
||||
final DummyClass1 other = (DummyClass1) o;
|
||||
return other.x == this.x;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class DummyClass2 {
|
||||
public DummyClass2(int x) {}
|
||||
}
|
||||
|
||||
private static final class DummyClass3 {}
|
||||
|
||||
static <T> void assertArraysEqual(T[] expected, T[] got) {
|
||||
if (expected.length != got.length) {
|
||||
fail(Arrays.toString(expected) + " and " + Arrays.toString(got)
|
||||
|
||||
Reference in New Issue
Block a user