1 /*
2  * Copyright (C) 2006 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 
17 package com.android.server.am;
18 
19 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
20 
21 import android.annotation.Nullable;
22 import android.app.IServiceConnection;
23 import android.app.PendingIntent;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.os.SystemClock;
27 import android.util.Slog;
28 import android.util.proto.ProtoOutputStream;
29 import android.util.proto.ProtoUtils;
30 
31 import com.android.internal.app.procstats.AssociationState;
32 import com.android.internal.app.procstats.ProcessStats;
33 import com.android.server.wm.ActivityServiceConnectionsHolder;
34 
35 import java.io.PrintWriter;
36 
37 /**
38  * Description of a single binding to a service.
39  */
40 final class ConnectionRecord {
41     final AppBindRecord binding;    // The application/service binding.
42     final ActivityServiceConnectionsHolder<ConnectionRecord> activity;  // If non-null, the owning activity.
43     final IServiceConnection conn;  // The client connection.
44     private final long flags;                // Binding options.
45     final int clientLabel;          // String resource labeling this client.
46     final PendingIntent clientIntent; // How to launch the client.
47     final int clientUid;            // The identity of this connection's client
48     final String clientProcessName; // The source process of this connection's client
49     final String clientPackageName; // The source package of this connection's client
50     public AssociationState.SourceState association; // Association tracking
51     String stringName;              // Caching of toString.
52     boolean serviceDead;            // Well is it?
53     private Object mProcStatsLock;  // Internal lock for accessing AssociationState
54     /**
55      * If the connection was made against an alias, then the alias conponent name. Otherwise, null.
56      * We return this component name to the client.
57      */
58     @Nullable
59     final ComponentName aliasComponent;
60 
61     // Please keep the following two enum list synced.
62     private static final int[] BIND_ORIG_ENUMS = new int[] {
63             Context.BIND_AUTO_CREATE,
64             Context.BIND_DEBUG_UNBIND,
65             Context.BIND_NOT_FOREGROUND,
66             Context.BIND_IMPORTANT_BACKGROUND,
67             Context.BIND_ABOVE_CLIENT,
68             Context.BIND_ALLOW_OOM_MANAGEMENT,
69             Context.BIND_WAIVE_PRIORITY,
70             Context.BIND_IMPORTANT,
71             Context.BIND_ADJUST_WITH_ACTIVITY,
72             Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
73             Context.BIND_FOREGROUND_SERVICE,
74             Context.BIND_TREAT_LIKE_ACTIVITY,
75             Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
76             Context.BIND_SHOWING_UI,
77             Context.BIND_NOT_VISIBLE,
78             Context.BIND_NOT_PERCEPTIBLE,
79             Context.BIND_INCLUDE_CAPABILITIES,
80             Context.BIND_ALLOW_ACTIVITY_STARTS,
81     };
82     private static final int[] BIND_PROTO_ENUMS = new int[] {
83             ConnectionRecordProto.AUTO_CREATE,
84             ConnectionRecordProto.DEBUG_UNBIND,
85             ConnectionRecordProto.NOT_FG,
86             ConnectionRecordProto.IMPORTANT_BG,
87             ConnectionRecordProto.ABOVE_CLIENT,
88             ConnectionRecordProto.ALLOW_OOM_MANAGEMENT,
89             ConnectionRecordProto.WAIVE_PRIORITY,
90             ConnectionRecordProto.IMPORTANT,
91             ConnectionRecordProto.ADJUST_WITH_ACTIVITY,
92             ConnectionRecordProto.FG_SERVICE_WHILE_AWAKE,
93             ConnectionRecordProto.FG_SERVICE,
94             ConnectionRecordProto.TREAT_LIKE_ACTIVITY,
95             ConnectionRecordProto.VISIBLE,
96             ConnectionRecordProto.SHOWING_UI,
97             ConnectionRecordProto.NOT_VISIBLE,
98             ConnectionRecordProto.NOT_PERCEPTIBLE,
99             ConnectionRecordProto.INCLUDE_CAPABILITIES,
100             ConnectionRecordProto.ALLOW_ACTIVITY_STARTS,
101     };
102 
dump(PrintWriter pw, String prefix)103     void dump(PrintWriter pw, String prefix) {
104         pw.println(prefix + "binding=" + binding);
105         if (activity != null) {
106             activity.dump(pw, prefix);
107         }
108         pw.println(prefix + "conn=" + conn.asBinder()
109                 + " flags=0x" + Long.toHexString(flags));
110     }
111 
ConnectionRecord(AppBindRecord _binding, ActivityServiceConnectionsHolder<ConnectionRecord> _activity, IServiceConnection _conn, long _flags, int _clientLabel, PendingIntent _clientIntent, int _clientUid, String _clientProcessName, String _clientPackageName, ComponentName _aliasComponent)112     ConnectionRecord(AppBindRecord _binding,
113             ActivityServiceConnectionsHolder<ConnectionRecord> _activity,
114             IServiceConnection _conn, long _flags,
115             int _clientLabel, PendingIntent _clientIntent,
116             int _clientUid, String _clientProcessName, String _clientPackageName,
117             ComponentName _aliasComponent) {
118         binding = _binding;
119         activity = _activity;
120         conn = _conn;
121         flags = _flags;
122         clientLabel = _clientLabel;
123         clientIntent = _clientIntent;
124         clientUid = _clientUid;
125         clientProcessName = _clientProcessName;
126         clientPackageName = _clientPackageName;
127         aliasComponent = _aliasComponent;
128     }
129 
getFlags()130     public long getFlags() {
131         return flags;
132     }
133 
hasFlag(final int flag)134     public boolean hasFlag(final int flag) {
135         return (flags & Integer.toUnsignedLong(flag)) != 0;
136     }
137 
hasFlag(final long flag)138     public boolean hasFlag(final long flag) {
139         return (flags & flag) != 0;
140     }
141 
notHasFlag(final int flag)142     public boolean notHasFlag(final int flag) {
143         return !hasFlag(flag);
144     }
145 
notHasFlag(final long flag)146     public boolean notHasFlag(final long flag) {
147         return !hasFlag(flag);
148     }
149 
startAssociationIfNeeded()150     public void startAssociationIfNeeded() {
151         // If we don't already have an active association, create one...  but only if this
152         // is an association between two different processes.
153         if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS
154                 && association == null && binding.service.app != null
155                 && (binding.service.appInfo.uid != clientUid
156                         || !binding.service.processName.equals(clientProcessName))) {
157             ProcessStats.ProcessStateHolder holder = binding.service.app.getPkgList().get(
158                     binding.service.instanceName.getPackageName());
159             if (holder == null) {
160                 Slog.wtf(TAG_AM, "No package in referenced service "
161                         + binding.service.shortInstanceName + ": proc=" + binding.service.app);
162             } else if (holder.pkg == null) {
163                 Slog.wtf(TAG_AM, "Inactive holder in referenced service "
164                         + binding.service.shortInstanceName + ": proc=" + binding.service.app);
165             } else {
166                 mProcStatsLock = binding.service.app.mService.mProcessStats.mLock;
167                 synchronized (mProcStatsLock) {
168                     association = holder.pkg.getAssociationStateLocked(holder.state,
169                             binding.service.instanceName.getClassName()).startSource(clientUid,
170                             clientProcessName, clientPackageName);
171                 }
172             }
173         }
174     }
175 
trackProcState(int procState, int seq)176     public void trackProcState(int procState, int seq) {
177         if (association != null) {
178             synchronized (mProcStatsLock) {
179                 association.trackProcState(procState, seq, SystemClock.uptimeMillis());
180             }
181         }
182     }
183 
stopAssociation()184     public void stopAssociation() {
185         if (association != null) {
186             synchronized (mProcStatsLock) {
187                 association.stop();
188             }
189             association = null;
190         }
191     }
192 
toString()193     public String toString() {
194         if (stringName != null) {
195             return stringName;
196         }
197         StringBuilder sb = new StringBuilder(128);
198         sb.append("ConnectionRecord{");
199         sb.append(Integer.toHexString(System.identityHashCode(this)));
200         sb.append(" u");
201         sb.append(binding.client.userId);
202         sb.append(' ');
203         if (hasFlag(Context.BIND_AUTO_CREATE)) {
204             sb.append("CR ");
205         }
206         if (hasFlag(Context.BIND_DEBUG_UNBIND)) {
207             sb.append("DBG ");
208         }
209         if (hasFlag(Context.BIND_NOT_FOREGROUND)) {
210             sb.append("!FG ");
211         }
212         if (hasFlag(Context.BIND_IMPORTANT_BACKGROUND)) {
213             sb.append("IMPB ");
214         }
215         if (hasFlag(Context.BIND_ABOVE_CLIENT)) {
216             sb.append("ABCLT ");
217         }
218         if (hasFlag(Context.BIND_ALLOW_OOM_MANAGEMENT)) {
219             sb.append("OOM ");
220         }
221         if (hasFlag(Context.BIND_WAIVE_PRIORITY)) {
222             sb.append("WPRI ");
223         }
224         if (hasFlag(Context.BIND_IMPORTANT)) {
225             sb.append("IMP ");
226         }
227         if (hasFlag(Context.BIND_ADJUST_WITH_ACTIVITY)) {
228             sb.append("WACT ");
229         }
230         if (hasFlag(Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)) {
231             sb.append("FGSA ");
232         }
233         if (hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
234             sb.append("FGS ");
235         }
236         if (hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
237             sb.append("LACT ");
238         }
239         if (hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP)) {
240             sb.append("SLTA ");
241         }
242         if (hasFlag(Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)) {
243             sb.append("VFGS ");
244         }
245         if (hasFlag(Context.BIND_SHOWING_UI)) {
246             sb.append("UI ");
247         }
248         if (hasFlag(Context.BIND_NOT_VISIBLE)) {
249             sb.append("!VIS ");
250         }
251         if (hasFlag(Context.BIND_NOT_PERCEPTIBLE)) {
252             sb.append("!PRCP ");
253         }
254         if (hasFlag(Context.BIND_ALLOW_ACTIVITY_STARTS)) {
255             sb.append("BALF ");
256         }
257         if (hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
258             sb.append("CAPS ");
259         }
260         if (serviceDead) {
261             sb.append("DEAD ");
262         }
263         sb.append(binding.service.shortInstanceName);
264         sb.append(":@");
265         sb.append(Integer.toHexString(System.identityHashCode(conn.asBinder())));
266         sb.append(" flags=0x" + Long.toHexString(flags));
267         sb.append('}');
268         return stringName = sb.toString();
269     }
270 
dumpDebug(ProtoOutputStream proto, long fieldId)271     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
272         if (binding == null) return; // if binding is null, don't write data, something is wrong.
273         long token = proto.start(fieldId);
274         proto.write(ConnectionRecordProto.HEX_HASH,
275                 Integer.toHexString(System.identityHashCode(this)));
276         if (binding.client != null) {
277             proto.write(ConnectionRecordProto.USER_ID, binding.client.userId);
278         }
279         ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, ConnectionRecordProto.FLAGS,
280                 flags, BIND_ORIG_ENUMS, BIND_PROTO_ENUMS);
281         if (serviceDead) {
282             proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.DEAD);
283         }
284         if (binding.service != null) {
285             proto.write(ConnectionRecordProto.SERVICE_NAME, binding.service.shortInstanceName);
286         }
287         proto.end(token);
288     }
289 }
290