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