163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon/* 263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Copyright (C) 2014 The Android Open Source Project 363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * 463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Licensed under the Apache License, Version 2.0 (the "License"); 563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * you may not use this file except in compliance with the License. 663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * You may obtain a copy of the License at 763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * 863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * http://www.apache.org/licenses/LICENSE-2.0 963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * 1063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Unless required by applicable law or agreed to in writing, software 1163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * distributed under the License is distributed on an "AS IS" BASIS, 1263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * See the License for the specific language governing permissions and 1463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * limitations under the License. 1563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 1663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 177cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnpackage com.android.server.telecom; 1863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 1963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport android.content.ComponentName; 2063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport android.content.Context; 2163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport android.content.Intent; 2263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport android.content.ServiceConnection; 2363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport android.os.IBinder; 24105d977687d1d0de7cd9420fc140b01404261df1Evan Charltonimport android.os.UserHandle; 254bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordonimport android.text.TextUtils; 264bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordonimport android.util.ArraySet; 2763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 2891d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunnimport com.android.internal.util.Preconditions; 295c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon 30a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shraunerimport java.util.Collections; 315c12c6e00101d16d2db776839a027c62c109dea8Santos Cordonimport java.util.Set; 32a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shraunerimport java.util.concurrent.ConcurrentHashMap; 3363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 3463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon/** 3563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Abstract class to perform the work of binding and unbinding to the specified service interface. 3663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Subclasses supply the service intent and component name and this class will invoke protected 3763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * methods when the class is bound, unbound, or upon failure. 3863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 3978a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awadabstract class ServiceBinder { 4063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 415c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon /** 425c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Callback to notify after a binding succeeds or fails. 435c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon */ 445c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon interface BindCallback { 45c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon void onSuccess(); 46c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon void onFailure(); 47c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 48c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 49c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon /** 50c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * Listener for bind events on ServiceBinder. 51c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon */ 5278a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad interface Listener<ServiceBinderClass extends ServiceBinder> { 5374d420be72fa30735fe9b7a25715f6db046c0398Santos Cordon void onUnbind(ServiceBinderClass serviceBinder); 545c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 555c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon 566192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad /** 576192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * Helper class to perform on-demand binding. 586192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad */ 598731faf3a1dcf888b894d4ad0faab97effab10bcIhab Awad final class Binder2 { 606192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad /** 616192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * Performs an asynchronous bind to the service (only if not already bound) and executes the 626192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * specified callback. 636192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * 646192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * @param callback The callback to notify of the binding's success or failure. 65165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon * @param call The call for which we are being bound. 666192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad */ 67165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon void bind(BindCallback callback, Call call) { 686192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad Log.d(ServiceBinder.this, "bind()"); 696192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 706192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad // Reset any abort request if we're asked to bind again. 716192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad clearAbort(); 726192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 736192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad if (!mCallbacks.isEmpty()) { 746192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad // Binding already in progress, append to the list of callbacks and bail out. 756192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad mCallbacks.add(callback); 766192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad return; 776192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 786192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 796192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad mCallbacks.add(callback); 806192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad if (mServiceConnection == null) { 816192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName); 82165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon ServiceConnection connection = new ServiceBinderConnection(call); 836192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 84165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon Log.event(call, Log.Events.BIND_CS, mComponentName); 858e6edbf6eede9221ad4ef30ffb7d6ff26553a329Santos Cordon final int bindingFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE; 868e6edbf6eede9221ad4ef30ffb7d6ff26553a329Santos Cordon final boolean isBound; 87105d977687d1d0de7cd9420fc140b01404261df1Evan Charlton if (mUserHandle != null) { 888e6edbf6eede9221ad4ef30ffb7d6ff26553a329Santos Cordon isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags, 898e6edbf6eede9221ad4ef30ffb7d6ff26553a329Santos Cordon mUserHandle); 90105d977687d1d0de7cd9420fc140b01404261df1Evan Charlton } else { 918e6edbf6eede9221ad4ef30ffb7d6ff26553a329Santos Cordon isBound = mContext.bindService(serviceIntent, connection, bindingFlags); 92105d977687d1d0de7cd9420fc140b01404261df1Evan Charlton } 938e6edbf6eede9221ad4ef30ffb7d6ff26553a329Santos Cordon if (!isBound) { 946192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad handleFailedConnection(); 956192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad return; 966192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 976192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } else { 986192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad Log.d(ServiceBinder.this, "Service is already bound."); 996192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad Preconditions.checkNotNull(mBinder); 1006192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad handleSuccessfulConnection(); 1016192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 1026192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 1036192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 1046192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 10563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private final class ServiceBinderConnection implements ServiceConnection { 106165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon /** 107165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon * The initial call for which the service was bound. 108165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon */ 109165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon private Call mCall; 110165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon 111165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon ServiceBinderConnection(Call call) { 112165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon mCall = call; 113165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon } 114165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon 11563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon @Override 11663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon public void onServiceConnected(ComponentName componentName, IBinder binder) { 1178d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad synchronized (mLock) { 1188d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad Log.i(this, "Service bound %s", componentName); 1198d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad 120165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon Log.event(mCall, Log.Events.CS_BOUND, componentName); 121165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon mCall = null; 122165c1ced107a1c3b9b359757d41438f9ca585e78Santos Cordon 1238d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad // Unbind request was queued so unbind immediately. 1248d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad if (mIsBindingAborted) { 1258d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad clearAbort(); 1268d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad logServiceDisconnected("onServiceConnected"); 1278d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad mContext.unbindService(this); 1288d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad handleFailedConnection(); 1298d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad return; 1308d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad } 13163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 1328d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad mServiceConnection = this; 1338d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad setBinder(binder); 1348d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad handleSuccessfulConnection(); 13563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 13663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 13763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 13863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon @Override 13963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon public void onServiceDisconnected(ComponentName componentName) { 1408d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad synchronized (mLock) { 1418d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad logServiceDisconnected("onServiceDisconnected"); 142c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 1438d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad mServiceConnection = null; 1448d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad clearAbort(); 14563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 1468d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad handleServiceDisconnected(); 1478d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad } 14863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 14963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 15063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 15163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** The application context. */ 15263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private final Context mContext; 15363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 1548d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad /** The Telecom lock object. */ 1558d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad protected final TelecomSystem.SyncRoot mLock; 1568d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad 15763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** The intent action to use when binding through {@link Context#bindService}. */ 15863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private final String mServiceAction; 15963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 16063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** The component name of the service to bind to. */ 16163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private final ComponentName mComponentName; 16263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 1635c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon /** The set of callbacks waiting for notification of the binding's success or failure. */ 1644bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon private final Set<BindCallback> mCallbacks = new ArraySet<>(); 1655c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon 16663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** Used to bind and unbind from the service. */ 16763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private ServiceConnection mServiceConnection; 16863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 169105d977687d1d0de7cd9420fc140b01404261df1Evan Charlton /** {@link UserHandle} to use for binding, to support work profiles and multi-user. */ 170105d977687d1d0de7cd9420fc140b01404261df1Evan Charlton private UserHandle mUserHandle; 171105d977687d1d0de7cd9420fc140b01404261df1Evan Charlton 17263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** The binder provided by {@link ServiceConnection#onServiceConnected} */ 17363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private IBinder mBinder; 17463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 1758e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad private int mAssociatedCallCount = 0; 1768e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 17763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 17863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Indicates that an unbind request was made when the service was not yet bound. If the service 17963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * successfully connects when this is true, it should be unbound immediately. 18063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 18163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private boolean mIsBindingAborted; 18263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 18363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 184c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * Set of currently registered listeners. 185a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 186a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner * load factor before resizing, 1 means we only expect a single thread to 187a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner * access the map so make only a single shard 188c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon */ 189a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner private final Set<Listener> mListeners = Collections.newSetFromMap( 190a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1)); 191c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 192c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon /** 19363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Persists the specified parameters and initializes the new instance. 19463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * 19563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * @param serviceAction The intent-action used with {@link Context#bindService}. 19663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * @param componentName The component name of the service with which to bind. 19791d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn * @param context The context. 198105d977687d1d0de7cd9420fc140b01404261df1Evan Charlton * @param userHandle The {@link UserHandle} to use for binding. 19963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 200105d977687d1d0de7cd9420fc140b01404261df1Evan Charlton protected ServiceBinder(String serviceAction, ComponentName componentName, Context context, 2018d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad TelecomSystem.SyncRoot lock, UserHandle userHandle) { 2024bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon Preconditions.checkState(!TextUtils.isEmpty(serviceAction)); 20363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon Preconditions.checkNotNull(componentName); 20463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 20591d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn mContext = context; 2068d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad mLock = lock; 20763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mServiceAction = serviceAction; 20863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mComponentName = componentName; 209105d977687d1d0de7cd9420fc140b01404261df1Evan Charlton mUserHandle = userHandle; 21063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 21163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 2128e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad final void incrementAssociatedCallCount() { 2138e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad mAssociatedCallCount++; 214c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon Log.v(this, "Call count increment %d, %s", mAssociatedCallCount, 215c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mComponentName.flattenToShortString()); 2168e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 2178e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 2188e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad final void decrementAssociatedCallCount() { 2198e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad if (mAssociatedCallCount > 0) { 2208e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad mAssociatedCallCount--; 221c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon Log.v(this, "Call count decrement %d, %s", mAssociatedCallCount, 222c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mComponentName.flattenToShortString()); 223c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 224c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon if (mAssociatedCallCount == 0) { 225c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon unbind(); 226c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 2278e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } else { 228f1c191d3974fed3f57680c63571ae0212c4622e7Sailesh Nepal Log.wtf(this, "%s: ignoring a request to decrement mAssociatedCallCount below zero", 229f1c191d3974fed3f57680c63571ae0212c4622e7Sailesh Nepal mComponentName.getClassName()); 2308e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 2318e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 2328e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 2338e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad final int getAssociatedCallCount() { 2348e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad return mAssociatedCallCount; 2358e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 2368e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 23763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 23863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Unbinds from the service if already bound, no-op otherwise. 23963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 24063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon final void unbind() { 24163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon if (mServiceConnection == null) { 24263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon // We're not yet bound, so queue up an abort request. 24363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mIsBindingAborted = true; 24463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } else { 245c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon logServiceDisconnected("unbind"); 24663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mContext.unbindService(mServiceConnection); 24763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mServiceConnection = null; 2486192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad setBinder(null); 24963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 25063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 25163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 252bb167cdd0dffa8103ba051b0e115dcaecf2b649dBen Gilad final ComponentName getComponentName() { 25363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon return mComponentName; 25463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 25563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 2566192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad final boolean isServiceValid(String actionName) { 2576192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad if (mBinder == null) { 258682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon Log.w(this, "%s invoked while service is unbound", actionName); 2596192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad return false; 2606192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 2616192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 2626192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad return true; 2636192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 2646192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 265c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon final void addListener(Listener listener) { 266c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mListeners.add(listener); 267c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 268c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 269c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon final void removeListener(Listener listener) { 270a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner if (listener != null) { 271a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner mListeners.remove(listener); 272a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner } 273c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 274c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 275c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon /** 276c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * Logs a standard message upon service disconnection. This method exists because there is no 277c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * single method called whenever the service unbinds and we want to log the same string in all 278c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * instances where that occurs. (Context.unbindService() does not cause onServiceDisconnected 279c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * to execute). 280c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * 281c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * @param sourceTag Tag to disambiguate 282c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon */ 283c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon private void logServiceDisconnected(String sourceTag) { 284c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon Log.i(this, "Service unbound %s, from %s.", mComponentName, sourceTag); 285c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 286c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 28763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 2885c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Notifies all the outstanding callbacks that the service is successfully bound. The list of 2895c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * outstanding callbacks is cleared afterwards. 29063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 291b6141aec99bcf399faea1bfc9f48503492c4fb2dSailesh Nepal private void handleSuccessfulConnection() { 2925c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon for (BindCallback callback : mCallbacks) { 2935c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon callback.onSuccess(); 2945c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 2955c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon mCallbacks.clear(); 2965c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 29763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 29863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 2995c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Notifies all the outstanding callbacks that the service failed to bind. The list of 3005c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * outstanding callbacks is cleared afterwards. 30163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 3025c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon private void handleFailedConnection() { 3035c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon for (BindCallback callback : mCallbacks) { 3045c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon callback.onFailure(); 3055c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 3065c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon mCallbacks.clear(); 3075c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 30863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 30963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 31063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Handles a service disconnection. 31163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 3125c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon private void handleServiceDisconnected() { 3136192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad setBinder(null); 3145c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 31563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 31663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private void clearAbort() { 31763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mIsBindingAborted = false; 31863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 3195c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon 3205c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon /** 3216192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * Sets the (private) binder and updates the child class. 3226192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * 3236192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * @param binder The new binder value. 3246192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad */ 3256192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad private void setBinder(IBinder binder) { 326c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon if (mBinder != binder) { 327c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mBinder = binder; 328c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 329c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon setServiceInterface(binder); 330c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 331c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon if (binder == null) { 332a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner for (Listener l : mListeners) { 333c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon l.onUnbind(this); 334c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 335c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 336c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 3376192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 3386192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 3396192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad /** 3405c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Sets the service interface after the service is bound or unbound. 3415c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * 3425c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * @param binder The actual bound service implementation. 3435c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon */ 3445c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon protected abstract void setServiceInterface(IBinder binder); 34563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon} 346