diff options
6 files changed, 617 insertions, 176 deletions
diff --git a/core/java/com/android/internal/util/RingBuffer.java b/core/java/com/android/internal/util/RingBuffer.java index c22be2ccf076..9a6e542ccbbd 100644 --- a/core/java/com/android/internal/util/RingBuffer.java +++ b/core/java/com/android/internal/util/RingBuffer.java @@ -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()); diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 1a196013b124..6fb3dbb75f3f 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -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 diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java new file mode 100644 index 000000000000..2bd9cab313a7 --- /dev/null +++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java @@ -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; + } + } +} diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 3fa3cd49d393..fdfe2418bcd2 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -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; diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 40788299a6c6..f093d57bcf48 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -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); diff --git a/tests/net/java/com/android/internal/util/RingBufferTest.java b/tests/net/java/com/android/internal/util/RingBufferTest.java index 7a2344317223..90a373a9c11e 100644 --- a/tests/net/java/com/android/internal/util/RingBufferTest.java +++ b/tests/net/java/com/android/internal/util/RingBufferTest.java @@ -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) |