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
17package com.android.server.am;
18
19import android.app.IServiceConnection;
20import android.app.PendingIntent;
21import android.content.Context;
22import android.util.proto.ProtoOutputStream;
23import android.util.proto.ProtoUtils;
24
25import java.io.PrintWriter;
26
27/**
28 * Description of a single binding to a service.
29 */
30final class ConnectionRecord {
31    final AppBindRecord binding;    // The application/service binding.
32    final ActivityRecord activity;  // If non-null, the owning activity.
33    final IServiceConnection conn;  // The client connection.
34    final int flags;                // Binding options.
35    final int clientLabel;          // String resource labeling this client.
36    final PendingIntent clientIntent; // How to launch the client.
37    String stringName;              // Caching of toString.
38    boolean serviceDead;            // Well is it?
39
40    // Please keep the following two enum list synced.
41    private static int[] BIND_ORIG_ENUMS = new int[] {
42            Context.BIND_AUTO_CREATE,
43            Context.BIND_DEBUG_UNBIND,
44            Context.BIND_NOT_FOREGROUND,
45            Context.BIND_IMPORTANT_BACKGROUND,
46            Context.BIND_ABOVE_CLIENT,
47            Context.BIND_ALLOW_OOM_MANAGEMENT,
48            Context.BIND_WAIVE_PRIORITY,
49            Context.BIND_IMPORTANT,
50            Context.BIND_ADJUST_WITH_ACTIVITY,
51            Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
52            Context.BIND_FOREGROUND_SERVICE,
53            Context.BIND_TREAT_LIKE_ACTIVITY,
54            Context.BIND_VISIBLE,
55            Context.BIND_SHOWING_UI,
56            Context.BIND_NOT_VISIBLE,
57    };
58    private static int[] BIND_PROTO_ENUMS = new int[] {
59            ConnectionRecordProto.AUTO_CREATE,
60            ConnectionRecordProto.DEBUG_UNBIND,
61            ConnectionRecordProto.NOT_FG,
62            ConnectionRecordProto.IMPORTANT_BG,
63            ConnectionRecordProto.ABOVE_CLIENT,
64            ConnectionRecordProto.ALLOW_OOM_MANAGEMENT,
65            ConnectionRecordProto.WAIVE_PRIORITY,
66            ConnectionRecordProto.IMPORTANT,
67            ConnectionRecordProto.ADJUST_WITH_ACTIVITY,
68            ConnectionRecordProto.FG_SERVICE_WHILE_AWAKE,
69            ConnectionRecordProto.FG_SERVICE,
70            ConnectionRecordProto.TREAT_LIKE_ACTIVITY,
71            ConnectionRecordProto.VISIBLE,
72            ConnectionRecordProto.SHOWING_UI,
73            ConnectionRecordProto.NOT_VISIBLE,
74    };
75
76    void dump(PrintWriter pw, String prefix) {
77        pw.println(prefix + "binding=" + binding);
78        if (activity != null) {
79            pw.println(prefix + "activity=" + activity);
80        }
81        pw.println(prefix + "conn=" + conn.asBinder()
82                + " flags=0x" + Integer.toHexString(flags));
83    }
84
85    ConnectionRecord(AppBindRecord _binding, ActivityRecord _activity,
86               IServiceConnection _conn, int _flags,
87               int _clientLabel, PendingIntent _clientIntent) {
88        binding = _binding;
89        activity = _activity;
90        conn = _conn;
91        flags = _flags;
92        clientLabel = _clientLabel;
93        clientIntent = _clientIntent;
94    }
95
96    public String toString() {
97        if (stringName != null) {
98            return stringName;
99        }
100        StringBuilder sb = new StringBuilder(128);
101        sb.append("ConnectionRecord{");
102        sb.append(Integer.toHexString(System.identityHashCode(this)));
103        sb.append(" u");
104        sb.append(binding.client.userId);
105        sb.append(' ');
106        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
107            sb.append("CR ");
108        }
109        if ((flags&Context.BIND_DEBUG_UNBIND) != 0) {
110            sb.append("DBG ");
111        }
112        if ((flags&Context.BIND_NOT_FOREGROUND) != 0) {
113            sb.append("!FG ");
114        }
115        if ((flags&Context.BIND_IMPORTANT_BACKGROUND) != 0) {
116            sb.append("IMPB ");
117        }
118        if ((flags&Context.BIND_ABOVE_CLIENT) != 0) {
119            sb.append("ABCLT ");
120        }
121        if ((flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
122            sb.append("OOM ");
123        }
124        if ((flags&Context.BIND_WAIVE_PRIORITY) != 0) {
125            sb.append("WPRI ");
126        }
127        if ((flags&Context.BIND_IMPORTANT) != 0) {
128            sb.append("IMP ");
129        }
130        if ((flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
131            sb.append("WACT ");
132        }
133        if ((flags&Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE) != 0) {
134            sb.append("FGSA ");
135        }
136        if ((flags&Context.BIND_FOREGROUND_SERVICE) != 0) {
137            sb.append("FGS ");
138        }
139        if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
140            sb.append("LACT ");
141        }
142        if ((flags&Context.BIND_VISIBLE) != 0) {
143            sb.append("VIS ");
144        }
145        if ((flags&Context.BIND_SHOWING_UI) != 0) {
146            sb.append("UI ");
147        }
148        if ((flags&Context.BIND_NOT_VISIBLE) != 0) {
149            sb.append("!VIS ");
150        }
151        if (serviceDead) {
152            sb.append("DEAD ");
153        }
154        sb.append(binding.service.shortName);
155        sb.append(":@");
156        sb.append(Integer.toHexString(System.identityHashCode(conn.asBinder())));
157        sb.append('}');
158        return stringName = sb.toString();
159    }
160
161    public void writeToProto(ProtoOutputStream proto, long fieldId) {
162        if (binding == null) return; // if binding is null, don't write data, something is wrong.
163        long token = proto.start(fieldId);
164        proto.write(ConnectionRecordProto.HEX_HASH,
165                Integer.toHexString(System.identityHashCode(this)));
166        if (binding.client != null) {
167            proto.write(ConnectionRecordProto.USER_ID, binding.client.userId);
168        }
169        ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, ConnectionRecordProto.FLAGS,
170                flags, BIND_ORIG_ENUMS, BIND_PROTO_ENUMS);
171        if (serviceDead) {
172            proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.DEAD);
173        }
174        if (binding.service != null) {
175            proto.write(ConnectionRecordProto.SERVICE_NAME, binding.service.shortName);
176        }
177        proto.end(token);
178    }
179}
180