Home | History | Annotate | Download | only in am
      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 
     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 
    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 
    116     public boolean hasFlag(final int flag) {
    117         return (flags & flag) != 0;
    118     }
    119 
    120     public boolean notHasFlag(final int flag) {
    121         return (flags & flag) == 0;
    122     }
    123 
    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 
    148     public void trackProcState(int procState, int seq, long now) {
    149         if (association != null) {
    150             association.trackProcState(procState, seq, now);
    151         }
    152     }
    153 
    154     public void stopAssociation() {
    155         if (association != null) {
    156             association.stop();
    157             association = null;
    158         }
    159     }
    160 
    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 
    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