NetworkPolicyLogger.java revision 352dc57186ff796dbb7a095c609d1a0bae5d3fca
1/*
2 * Copyright (C) 2017 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 */
16package com.android.server.net;
17
18import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
19import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
20import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
21import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
22import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
23import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
24import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
25import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
26import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
27
28import android.app.ActivityManager;
29import android.net.NetworkPolicyManager;
30import android.util.Log;
31import android.util.Slog;
32
33import com.android.internal.util.IndentingPrintWriter;
34import com.android.internal.util.RingBuffer;
35import com.android.server.am.ProcessList;
36
37import java.text.SimpleDateFormat;
38import java.util.Arrays;
39import java.util.Date;
40
41public class NetworkPolicyLogger {
42    static final String TAG = "NetworkPolicy";
43
44    static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
45    static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE);
46
47    private static final int MAX_LOG_SIZE =
48            ActivityManager.isLowRamDeviceStatic() ? 20 : 50;
49    private static final int MAX_NETWORK_BLOCKED_LOG_SIZE =
50            ActivityManager.isLowRamDeviceStatic() ? 50 : 100;
51
52    private static final int EVENT_TYPE_GENERIC = 0;
53    private static final int EVENT_NETWORK_BLOCKED = 1;
54    private static final int EVENT_UID_STATE_CHANGED = 2;
55    private static final int EVENT_POLICIES_CHANGED = 3;
56    private static final int EVENT_METEREDNESS_CHANGED = 4;
57    private static final int EVENT_USER_STATE_REMOVED = 5;
58    private static final int EVENT_RESTRICT_BG_CHANGED = 6;
59    private static final int EVENT_DEVICE_IDLE_MODE_ENABLED = 7;
60    private static final int EVENT_APP_IDLE_STATE_CHANGED = 8;
61    private static final int EVENT_PAROLE_STATE_CHANGED = 9;
62    private static final int EVENT_TEMP_POWER_SAVE_WL_CHANGED = 10;
63    private static final int EVENT_UID_FIREWALL_RULE_CHANGED = 11;
64    private static final int EVENT_FIREWALL_CHAIN_ENABLED = 12;
65
66    static final int NTWK_BLOCKED_POWER = 0;
67    static final int NTWK_ALLOWED_NON_METERED = 1;
68    static final int NTWK_BLOCKED_BLACKLIST = 2;
69    static final int NTWK_ALLOWED_WHITELIST = 3;
70    static final int NTWK_ALLOWED_TMP_WHITELIST = 4;
71    static final int NTWK_BLOCKED_BG_RESTRICT = 5;
72    static final int NTWK_ALLOWED_DEFAULT = 6;
73
74    private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE);
75    private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE);
76    private final LogBuffer mEventsBuffer = new LogBuffer(MAX_LOG_SIZE);
77
78    private final Object mLock = new Object();
79
80    void networkBlocked(int uid, int reason) {
81        synchronized (mLock) {
82            if (LOGD) Slog.d(TAG, uid + " is " + getBlockedReason(reason));
83            mNetworkBlockedBuffer.networkBlocked(uid, reason);
84        }
85    }
86
87    void uidStateChanged(int uid, int procState, long procStateSeq) {
88        synchronized (mLock) {
89            if (LOGV) Slog.v(TAG,
90                    uid + " state changed to " + procState + " with seq=" + procStateSeq);
91            mUidStateChangeBuffer.uidStateChanged(uid, procState, procStateSeq);
92        }
93    }
94
95    void event(String msg) {
96        synchronized (mLock) {
97            if (LOGV) Slog.v(TAG, msg);
98            mEventsBuffer.event(msg);
99        }
100    }
101
102    void uidPolicyChanged(int uid, int oldPolicy, int newPolicy) {
103        synchronized (mLock) {
104            if (LOGV) Slog.v(TAG, getPolicyChangedLog(uid, oldPolicy, newPolicy));
105            mEventsBuffer.uidPolicyChanged(uid, oldPolicy, newPolicy);
106        }
107    }
108
109    void meterednessChanged(int netId, boolean newMetered) {
110        synchronized (mLock) {
111            if (LOGD) Slog.d(TAG, getMeterednessChangedLog(netId, newMetered));
112            mEventsBuffer.meterednessChanged(netId, newMetered);
113        }
114    }
115
116    void removingUserState(int userId) {
117        synchronized (mLock) {
118            if (LOGD) Slog.d(TAG, getUserRemovedLog(userId));
119            mEventsBuffer.userRemoved(userId);
120        }
121    }
122
123    void restrictBackgroundChanged(boolean oldValue, boolean newValue) {
124        synchronized (mLock) {
125            if (LOGD) Slog.d(TAG,
126                    getRestrictBackgroundChangedLog(oldValue, newValue));
127            mEventsBuffer.restrictBackgroundChanged(oldValue, newValue);
128        }
129    }
130
131    void deviceIdleModeEnabled(boolean enabled) {
132        synchronized (mLock) {
133            if (LOGD) Slog.d(TAG, getDeviceIdleModeEnabled(enabled));
134            mEventsBuffer.deviceIdleModeEnabled(enabled);
135        }
136    }
137
138    void appIdleStateChanged(int uid, boolean idle) {
139        synchronized (mLock) {
140            if (LOGD) Slog.d(TAG, getAppIdleChangedLog(uid, idle));
141            mEventsBuffer.appIdleStateChanged(uid, idle);
142        }
143    }
144
145    void paroleStateChanged(boolean paroleOn) {
146        synchronized (mLock) {
147            if (LOGD) Slog.d(TAG, getParoleStateChanged(paroleOn));
148            mEventsBuffer.paroleStateChanged(paroleOn);
149        }
150    }
151
152    void tempPowerSaveWlChanged(int appId, boolean added) {
153        synchronized (mLock) {
154            if (LOGV) Slog.v(TAG, getTempPowerSaveWlChangedLog(appId, added));
155            mEventsBuffer.tempPowerSaveWlChanged(appId, added);
156        }
157    }
158
159    void uidFirewallRuleChanged(int chain, int uid, int rule) {
160        synchronized (mLock) {
161            if (LOGV) Slog.v(TAG, getUidFirewallRuleChangedLog(chain, uid, rule));
162            mEventsBuffer.uidFirewallRuleChanged(chain, uid, rule);
163        }
164    }
165
166    void firewallChainEnabled(int chain, boolean enabled) {
167        synchronized (mLock) {
168            if (LOGD) Slog.d(TAG, getFirewallChainEnabledLog(chain, enabled));
169            mEventsBuffer.firewallChainEnabled(chain, enabled);
170        }
171    }
172
173    void firewallRulesChanged(int chain, int[] uids, int[] rules) {
174        synchronized (mLock) {
175            final String log = "Firewall rules changed for " + getFirewallChainName(chain)
176                    + "; uids=" + Arrays.toString(uids) + "; rules=" + Arrays.toString(rules);
177            if (LOGD) Slog.d(TAG, log);
178            mEventsBuffer.event(log);
179        }
180    }
181
182    void dumpLogs(IndentingPrintWriter pw) {
183        synchronized (mLock) {
184            pw.println();
185            pw.println("mEventLogs (most recent first):");
186            pw.increaseIndent();
187            mEventsBuffer.reverseDump(pw);
188            pw.decreaseIndent();
189
190            pw.println();
191            pw.println("mNetworkBlockedLogs (most recent first):");
192            pw.increaseIndent();
193            mNetworkBlockedBuffer.reverseDump(pw);
194            pw.decreaseIndent();
195
196            pw.println();
197            pw.println("mUidStateChangeLogs (most recent first):");
198            pw.increaseIndent();
199            mUidStateChangeBuffer.reverseDump(pw);
200            pw.decreaseIndent();
201        }
202    }
203
204    private static String getBlockedReason(int reason) {
205        switch (reason) {
206            case NTWK_BLOCKED_POWER:
207                return "blocked by power restrictions";
208            case NTWK_ALLOWED_NON_METERED:
209                return "allowed on unmetered network";
210            case NTWK_BLOCKED_BLACKLIST:
211                return "blacklisted on metered network";
212            case NTWK_ALLOWED_WHITELIST:
213                return "whitelisted on metered network";
214            case NTWK_ALLOWED_TMP_WHITELIST:
215                return "temporary whitelisted on metered network";
216            case NTWK_BLOCKED_BG_RESTRICT:
217                return "blocked when background is restricted";
218            case NTWK_ALLOWED_DEFAULT:
219                return "allowed by default";
220            default:
221                return String.valueOf(reason);
222        }
223    }
224
225    private static String getPolicyChangedLog(int uid, int oldPolicy, int newPolicy) {
226        return "Policy for " + uid + " changed from "
227                + NetworkPolicyManager.uidPoliciesToString(oldPolicy) + " to "
228                + NetworkPolicyManager.uidPoliciesToString(newPolicy);
229    }
230
231    private static String getMeterednessChangedLog(int netId, boolean newMetered) {
232        return "Meteredness of netId=" + netId + " changed to " + newMetered;
233    }
234
235    private static String getUserRemovedLog(int userId) {
236        return "Remove state for u" + userId;
237    }
238
239    private static String getRestrictBackgroundChangedLog(boolean oldValue, boolean newValue) {
240        return "Changed restrictBackground: " + oldValue + "->" + newValue;
241    }
242
243    private static String getDeviceIdleModeEnabled(boolean enabled) {
244        return "DeviceIdleMode enabled: " + enabled;
245    }
246
247    private static String getAppIdleChangedLog(int uid, boolean idle) {
248        return "App idle state of uid " + uid + ": " + idle;
249    }
250
251    private static String getParoleStateChanged(boolean paroleOn) {
252        return "Parole state: " + paroleOn;
253    }
254
255    private static String getTempPowerSaveWlChangedLog(int appId, boolean added) {
256        return "temp-power-save whitelist for " + appId + " changed to: " + added;
257    }
258
259    private static String getUidFirewallRuleChangedLog(int chain, int uid, int rule) {
260        return String.format("Firewall rule changed: %d-%s-%s",
261                uid, getFirewallChainName(chain), getFirewallRuleName(rule));
262    }
263
264    private static String getFirewallChainEnabledLog(int chain, boolean enabled) {
265        return "Firewall chain " + getFirewallChainName(chain) + " state: " + enabled;
266    }
267
268    private static String getFirewallChainName(int chain) {
269        switch (chain) {
270            case FIREWALL_CHAIN_DOZABLE:
271                return FIREWALL_CHAIN_NAME_DOZABLE;
272            case FIREWALL_CHAIN_STANDBY:
273                return FIREWALL_CHAIN_NAME_STANDBY;
274            case FIREWALL_CHAIN_POWERSAVE:
275                return FIREWALL_CHAIN_NAME_POWERSAVE;
276            default:
277                return String.valueOf(chain);
278        }
279    }
280
281    private static String getFirewallRuleName(int rule) {
282        switch (rule) {
283            case FIREWALL_RULE_DEFAULT:
284                return "default";
285            case FIREWALL_RULE_ALLOW:
286                return "allow";
287            case FIREWALL_RULE_DENY:
288                return "deny";
289            default:
290                return String.valueOf(rule);
291        }
292    }
293
294    private final static class LogBuffer extends RingBuffer<Data> {
295        private static final SimpleDateFormat sFormatter
296                = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss:SSS");
297        private static final Date sDate = new Date();
298
299        public LogBuffer(int capacity) {
300            super(Data.class, capacity);
301        }
302
303        public void uidStateChanged(int uid, int procState, long procStateSeq) {
304            final Data data = getNextSlot();
305            if (data == null) return;
306
307            data.reset();
308            data.type = EVENT_UID_STATE_CHANGED;
309            data.ifield1 = uid;
310            data.ifield2 = procState;
311            data.lfield1 = procStateSeq;
312            data.timeStamp = System.currentTimeMillis();
313        }
314
315        public void event(String msg) {
316            final Data data = getNextSlot();
317            if (data == null) return;
318
319            data.reset();
320            data.type = EVENT_TYPE_GENERIC;
321            data.sfield1 = msg;
322            data.timeStamp = System.currentTimeMillis();
323        }
324
325        public void networkBlocked(int uid, int reason) {
326            final Data data = getNextSlot();
327            if (data == null) return;
328
329            data.reset();
330            data.type = EVENT_NETWORK_BLOCKED;
331            data.ifield1 = uid;
332            data.ifield2 = reason;
333            data.timeStamp = System.currentTimeMillis();
334        }
335
336        public void uidPolicyChanged(int uid, int oldPolicy, int newPolicy) {
337            final Data data = getNextSlot();
338            if (data == null) return;
339
340            data.reset();
341            data.type = EVENT_POLICIES_CHANGED;
342            data.ifield1 = uid;
343            data.ifield2 = oldPolicy;
344            data.ifield3 = newPolicy;
345            data.timeStamp = System.currentTimeMillis();
346        }
347
348        public void meterednessChanged(int netId, boolean newMetered) {
349            final Data data = getNextSlot();
350            if (data == null) return;
351
352            data.reset();
353            data.type = EVENT_METEREDNESS_CHANGED;
354            data.ifield1 = netId;
355            data.bfield1 = newMetered;
356            data.timeStamp = System.currentTimeMillis();
357        }
358
359        public void userRemoved(int userId) {
360            final Data data = getNextSlot();
361            if (data == null) return;
362
363            data.reset();
364            data.type = EVENT_USER_STATE_REMOVED;
365            data.ifield1 = userId;
366            data.timeStamp = System.currentTimeMillis();
367        }
368
369        public void restrictBackgroundChanged(boolean oldValue, boolean newValue) {
370            final Data data = getNextSlot();
371            if (data == null) return;
372
373            data.reset();
374            data.type = EVENT_RESTRICT_BG_CHANGED;
375            data.bfield1 = oldValue;
376            data.bfield2 = newValue;
377            data.timeStamp = System.currentTimeMillis();
378        }
379
380        public void deviceIdleModeEnabled(boolean enabled) {
381            final Data data = getNextSlot();
382            if (data == null) return;
383
384            data.reset();
385            data.type = EVENT_DEVICE_IDLE_MODE_ENABLED;
386            data.bfield1 = enabled;
387            data.timeStamp = System.currentTimeMillis();
388        }
389
390        public void appIdleStateChanged(int uid, boolean idle) {
391            final Data data = getNextSlot();
392            if (data == null) return;
393
394            data.reset();
395            data.type = EVENT_APP_IDLE_STATE_CHANGED;
396            data.ifield1 = uid;
397            data.bfield1 = idle;
398            data.timeStamp = System.currentTimeMillis();
399        }
400
401        public void paroleStateChanged(boolean paroleOn) {
402            final Data data = getNextSlot();
403            if (data == null) return;
404
405            data.reset();
406            data.type = EVENT_PAROLE_STATE_CHANGED;
407            data.bfield1 = paroleOn;
408            data.timeStamp = System.currentTimeMillis();
409        }
410
411        public void tempPowerSaveWlChanged(int appId, boolean added) {
412            final Data data = getNextSlot();
413            if (data == null) return;
414
415            data.reset();
416            data.type = EVENT_TEMP_POWER_SAVE_WL_CHANGED;
417            data.ifield1 = appId;
418            data.bfield1 = added;
419            data.timeStamp = System.currentTimeMillis();
420        }
421
422        public void uidFirewallRuleChanged(int chain, int uid, int rule) {
423            final Data data = getNextSlot();
424            if (data == null) return;
425
426            data.reset();
427            data.type = EVENT_UID_FIREWALL_RULE_CHANGED;
428            data.ifield1 = chain;
429            data.ifield2 = uid;
430            data.ifield3 = rule;
431            data.timeStamp = System.currentTimeMillis();
432        }
433
434        public void firewallChainEnabled(int chain, boolean enabled) {
435            final Data data = getNextSlot();
436            if (data == null) return;
437
438            data.reset();
439            data.type = EVENT_FIREWALL_CHAIN_ENABLED;
440            data.ifield1 = chain;
441            data.bfield1 = enabled;
442            data.timeStamp = System.currentTimeMillis();
443        }
444
445        public void reverseDump(IndentingPrintWriter pw) {
446            final Data[] allData = toArray();
447            for (int i = allData.length - 1; i >= 0; --i) {
448                if (allData[i] == null) {
449                    pw.println("NULL");
450                    continue;
451                }
452                pw.print(formatDate(allData[i].timeStamp));
453                pw.print(" - ");
454                pw.println(getContent(allData[i]));
455            }
456        }
457
458        public String getContent(Data data) {
459            switch (data.type) {
460                case EVENT_TYPE_GENERIC:
461                    return data.sfield1;
462                case EVENT_NETWORK_BLOCKED:
463                    return data.ifield1 + "-" + getBlockedReason(data.ifield2);
464                case EVENT_UID_STATE_CHANGED:
465                    return data.ifield1 + "-" + ProcessList.makeProcStateString(data.ifield2)
466                            + "-" + data.lfield1;
467                case EVENT_POLICIES_CHANGED:
468                    return getPolicyChangedLog(data.ifield1, data.ifield2, data.ifield3);
469                case EVENT_METEREDNESS_CHANGED:
470                    return getMeterednessChangedLog(data.ifield1, data.bfield1);
471                case EVENT_USER_STATE_REMOVED:
472                    return getUserRemovedLog(data.ifield1);
473                case EVENT_RESTRICT_BG_CHANGED:
474                    return getRestrictBackgroundChangedLog(data.bfield1, data.bfield2);
475                case EVENT_DEVICE_IDLE_MODE_ENABLED:
476                    return getDeviceIdleModeEnabled(data.bfield1);
477                case EVENT_APP_IDLE_STATE_CHANGED:
478                    return getAppIdleChangedLog(data.ifield1, data.bfield1);
479                case EVENT_PAROLE_STATE_CHANGED:
480                    return getParoleStateChanged(data.bfield1);
481                case EVENT_TEMP_POWER_SAVE_WL_CHANGED:
482                    return getTempPowerSaveWlChangedLog(data.ifield1, data.bfield1);
483                case EVENT_UID_FIREWALL_RULE_CHANGED:
484                    return getUidFirewallRuleChangedLog(data.ifield1, data.ifield2, data.ifield3);
485                case EVENT_FIREWALL_CHAIN_ENABLED:
486                    return getFirewallChainEnabledLog(data.ifield1, data.bfield1);
487                default:
488                    return String.valueOf(data.type);
489            }
490        }
491
492        private String formatDate(long millis) {
493            sDate.setTime(millis);
494            return sFormatter.format(sDate);
495        }
496    }
497
498    public final static class Data {
499        int type;
500        long timeStamp;
501
502        int ifield1;
503        int ifield2;
504        int ifield3;
505        long lfield1;
506        boolean bfield1;
507        boolean bfield2;
508        String sfield1;
509
510        public void reset(){
511            sfield1 = null;
512        }
513    }
514}
515