1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import android.Manifest;
20import android.app.ActivityManager;
21import android.app.ActivityManagerProto;
22import android.content.pm.PackageManager;
23import android.os.SystemClock;
24import android.os.UserHandle;
25import android.util.TimeUtils;
26import android.util.proto.ProtoOutputStream;
27import android.util.proto.ProtoUtils;
28
29import com.android.internal.annotations.GuardedBy;
30import com.android.internal.annotations.VisibleForTesting;
31
32/**
33 * Overall information about a uid that has actively running processes.
34 */
35public final class UidRecord {
36    final int uid;
37    int curProcState;
38    int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
39    long lastBackgroundTime;
40    boolean ephemeral;
41    boolean foregroundServices;
42    boolean curWhitelist;
43    boolean setWhitelist;
44    boolean idle;
45    boolean setIdle;
46    int numProcs;
47
48    /**
49     * Sequence number associated with the {@link #curProcState}. This is incremented using
50     * {@link ActivityManagerService#mProcStateSeqCounter}
51     * when {@link #curProcState} changes from background to foreground or vice versa.
52     */
53    @GuardedBy("networkStateUpdate")
54    long curProcStateSeq;
55
56    /**
57     * Last seq number for which NetworkPolicyManagerService notified ActivityManagerService that
58     * network policies rules were updated.
59     */
60    @GuardedBy("networkStateUpdate")
61    long lastNetworkUpdatedProcStateSeq;
62
63    /**
64     * Last seq number for which AcitivityManagerService dispatched uid state change to
65     * NetworkPolicyManagerService.
66     */
67    @GuardedBy("networkStateUpdate")
68    long lastDispatchedProcStateSeq;
69
70    /**
71     * Indicates if any thread is waiting for network rules to get updated for {@link #uid}.
72     */
73    volatile boolean waitingForNetwork;
74
75    /**
76     * Indicates whether this uid has internet permission or not.
77     */
78    volatile boolean hasInternetPermission;
79
80    /**
81     * This object is used for waiting for the network state to get updated.
82     */
83    final Object networkStateLock = new Object();
84
85    static final int CHANGE_PROCSTATE = 0;
86    static final int CHANGE_GONE = 1<<0;
87    static final int CHANGE_IDLE = 1<<1;
88    static final int CHANGE_ACTIVE = 1<<2;
89    static final int CHANGE_CACHED = 1<<3;
90    static final int CHANGE_UNCACHED = 1<<4;
91
92    // Keep the enum lists in sync
93    private static int[] ORIG_ENUMS = new int[] {
94            CHANGE_GONE,
95            CHANGE_IDLE,
96            CHANGE_ACTIVE,
97            CHANGE_CACHED,
98            CHANGE_UNCACHED,
99    };
100    private static int[] PROTO_ENUMS = new int[] {
101            UidRecordProto.CHANGE_GONE,
102            UidRecordProto.CHANGE_IDLE,
103            UidRecordProto.CHANGE_ACTIVE,
104            UidRecordProto.CHANGE_CACHED,
105            UidRecordProto.CHANGE_UNCACHED,
106    };
107
108    static final class ChangeItem {
109        UidRecord uidRecord;
110        int uid;
111        int change;
112        int processState;
113        boolean ephemeral;
114        long procStateSeq;
115    }
116
117    ChangeItem pendingChange;
118    int lastReportedChange;
119
120    public UidRecord(int _uid) {
121        uid = _uid;
122        idle = true;
123        reset();
124    }
125
126    public void reset() {
127        curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
128        foregroundServices = false;
129    }
130
131    public void updateHasInternetPermission() {
132        hasInternetPermission = ActivityManager.checkUidPermission(Manifest.permission.INTERNET,
133                uid) == PackageManager.PERMISSION_GRANTED;
134    }
135
136    /**
137     * If the change being dispatched is not CHANGE_GONE (not interested in
138     * these changes), then update the {@link #lastDispatchedProcStateSeq} with
139     * {@link #curProcStateSeq}.
140     */
141    public void updateLastDispatchedProcStateSeq(int changeToDispatch) {
142        if ((changeToDispatch & CHANGE_GONE) == 0) {
143            lastDispatchedProcStateSeq = curProcStateSeq;
144        }
145    }
146
147
148    void writeToProto(ProtoOutputStream proto, long fieldId) {
149        long token = proto.start(fieldId);
150        proto.write(UidRecordProto.UID, uid);
151        proto.write(UidRecordProto.CURRENT, ProcessList.makeProcStateProtoEnum(curProcState));
152        proto.write(UidRecordProto.EPHEMERAL, ephemeral);
153        proto.write(UidRecordProto.FG_SERVICES, foregroundServices);
154        proto.write(UidRecordProto.WHILELIST, curWhitelist);
155        ProtoUtils.toDuration(proto, UidRecordProto.LAST_BACKGROUND_TIME,
156                lastBackgroundTime, SystemClock.elapsedRealtime());
157        proto.write(UidRecordProto.IDLE, idle);
158        if (lastReportedChange != 0) {
159            ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, UidRecordProto.LAST_REPORTED_CHANGES,
160                    lastReportedChange, ORIG_ENUMS, PROTO_ENUMS);
161        }
162        proto.write(UidRecordProto.NUM_PROCS, numProcs);
163
164        long seqToken = proto.start(UidRecordProto.NETWORK_STATE_UPDATE);
165        proto.write(UidRecordProto.ProcStateSequence.CURURENT, curProcStateSeq);
166        proto.write(UidRecordProto.ProcStateSequence.LAST_NETWORK_UPDATED,
167                lastNetworkUpdatedProcStateSeq);
168        proto.write(UidRecordProto.ProcStateSequence.LAST_DISPATCHED, lastDispatchedProcStateSeq);
169        proto.end(seqToken);
170
171        proto.end(token);
172    }
173
174    public String toString() {
175        StringBuilder sb = new StringBuilder(128);
176        sb.append("UidRecord{");
177        sb.append(Integer.toHexString(System.identityHashCode(this)));
178        sb.append(' ');
179        UserHandle.formatUid(sb, uid);
180        sb.append(' ');
181        sb.append(ProcessList.makeProcStateString(curProcState));
182        if (ephemeral) {
183            sb.append(" ephemeral");
184        }
185        if (foregroundServices) {
186            sb.append(" fgServices");
187        }
188        if (curWhitelist) {
189            sb.append(" whitelist");
190        }
191        if (lastBackgroundTime > 0) {
192            sb.append(" bg:");
193            TimeUtils.formatDuration(SystemClock.elapsedRealtime()-lastBackgroundTime, sb);
194        }
195        if (idle) {
196            sb.append(" idle");
197        }
198        if (lastReportedChange != 0) {
199            sb.append(" change:");
200            boolean printed = false;
201            if ((lastReportedChange & CHANGE_GONE) != 0) {
202                printed = true;
203                sb.append("gone");
204            }
205            if ((lastReportedChange & CHANGE_IDLE) != 0) {
206                if (printed) {
207                    sb.append("|");
208                }
209                printed = true;
210                sb.append("idle");
211            }
212            if ((lastReportedChange & CHANGE_ACTIVE) != 0) {
213                if (printed) {
214                    sb.append("|");
215                }
216                printed = true;
217                sb.append("active");
218            }
219            if ((lastReportedChange & CHANGE_CACHED) != 0) {
220                if (printed) {
221                    sb.append("|");
222                }
223                printed = true;
224                sb.append("cached");
225            }
226            if ((lastReportedChange & CHANGE_UNCACHED) != 0) {
227                if (printed) {
228                    sb.append("|");
229                }
230                sb.append("uncached");
231            }
232        }
233        sb.append(" procs:");
234        sb.append(numProcs);
235        sb.append(" seq(");
236        sb.append(curProcStateSeq);
237        sb.append(",");
238        sb.append(lastNetworkUpdatedProcStateSeq);
239        sb.append(",");
240        sb.append(lastDispatchedProcStateSeq);
241        sb.append(")}");
242        return sb.toString();
243    }
244}
245