1ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito/* 2ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * Copyright (C) 2015 The Android Open Source Project 3ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * 4ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * Licensed under the Apache License, Version 2.0 (the "License"); 5ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * you may not use this file except in compliance with the License. 6ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * You may obtain a copy of the License at 7ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * 8ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * http://www.apache.org/licenses/LICENSE-2.0 9ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * 10ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * Unless required by applicable law or agreed to in writing, software 11ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * distributed under the License is distributed on an "AS IS" BASIS, 12ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * See the License for the specific language governing permissions and 14ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito * limitations under the License. 15ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito */ 16ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 17ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itopackage com.android.nfc.cardemulation; 18ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 19ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.content.ComponentName; 20ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.content.Context; 21ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.content.Intent; 22ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.content.ServiceConnection; 23ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.nfc.cardemulation.NfcFServiceInfo; 24ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.nfc.cardemulation.HostNfcFService; 25ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.os.Bundle; 26ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.os.Handler; 27ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.os.IBinder; 28ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.os.Message; 29ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.os.Messenger; 30ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.os.RemoteException; 31ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.os.UserHandle; 32ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport android.util.Log; 33ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 34ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport com.android.nfc.NfcService; 35ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 36ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport java.io.FileDescriptor; 37ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itoimport java.io.PrintWriter; 38ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 39ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Itopublic class HostNfcFEmulationManager { 40ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito static final String TAG = "HostNfcFEmulationManager"; 41ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito static final boolean DBG = false; 42ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 43ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito static final int STATE_IDLE = 0; 44ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito static final int STATE_W4_SERVICE = 1; 45ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito static final int STATE_XFER = 2; 46ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 47ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito /** NFCID2 length */ 48ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito static final int NFCID2_LENGTH = 8; 49ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 50ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito /** Minimum NFC-F packets including length, command code and NFCID2 */ 51ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito static final int MINIMUM_NFCF_PACKET_LENGTH = 10; 52ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 53ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito final Context mContext; 54ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito final RegisteredT3tIdentifiersCache mT3tIdentifiersCache; 55ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito final Messenger mMessenger = new Messenger (new MessageHandler()); 56ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito final Object mLock; 57ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 58ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito // All variables below protected by mLock 59ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito ComponentName mEnabledFgServiceName; 60ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 61ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Messenger mService; 62ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito boolean mServiceBound; 63ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito ComponentName mServiceName; 64ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 65ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito // mActiveService denotes the service interface 66ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito // that is the current active one, until a new packet 67ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito // comes in that may be resolved to a different service. 68ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito // On deactivation, mActiveService stops being valid. 69ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Messenger mActiveService; 70ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito ComponentName mActiveServiceName; 71ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 72ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito int mState; 73ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito byte[] mPendingPacket; 74ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 75ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito public HostNfcFEmulationManager(Context context, 76ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito RegisteredT3tIdentifiersCache t3tIdentifiersCache) { 77ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mContext = context; 78ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mLock = new Object(); 79ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mEnabledFgServiceName = null; 80ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mT3tIdentifiersCache = t3tIdentifiersCache; 81ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mState = STATE_IDLE; 82ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 83ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 84ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito public void onEnabledForegroundNfcFServiceChanged(ComponentName service) { 85ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito synchronized (mLock) { 86ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mEnabledFgServiceName = service; 87ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (service == null) { 88ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito sendDeactivateToActiveServiceLocked(HostNfcFService.DEACTIVATION_LINK_LOSS); 89ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito unbindServiceIfNeededLocked(); 90ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 91ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 92ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 93ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 94ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito public void onHostEmulationActivated() { 95ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "notifyHostEmulationActivated"); 96ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 97ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 98ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito public void onHostEmulationData(byte[] data) { 99ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "notifyHostEmulationData"); 100ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito String nfcid2 = findNfcid2(data); 101ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito ComponentName resolvedServiceName = null; 102ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito synchronized (mLock) { 103ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (nfcid2 != null) { 104ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito NfcFServiceInfo resolvedService = mT3tIdentifiersCache.resolveNfcid2(nfcid2); 105ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (resolvedService != null) { 106ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito resolvedServiceName = resolvedService.getComponent(); 107ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 108ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 109ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (resolvedServiceName == null) { 110ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (mActiveServiceName == null) { 111ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return; 112ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 113ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito resolvedServiceName = mActiveServiceName; 114ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 115ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito // Check if resolvedService is actually currently enabled 116ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (mEnabledFgServiceName == null || 117ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito !mEnabledFgServiceName.equals(resolvedServiceName)) { 118ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return; 119ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 120ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "resolvedServiceName: " + resolvedServiceName.toString() + 121ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito "mState: " + String.valueOf(mState)); 122ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito switch (mState) { 123ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito case STATE_IDLE: 124ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Messenger existingService = bindServiceIfNeededLocked(resolvedServiceName); 125ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (existingService != null) { 126ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Binding to existing service"); 127ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mState = STATE_XFER; 128ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito sendDataToServiceLocked(existingService, data); 129ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } else { 130ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito // Waiting for service to be bound 131ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Waiting for new service."); 132ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito // Queue packet to be used 133ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mPendingPacket = data; 134ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mState = STATE_W4_SERVICE; 135ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 136ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito break; 137ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito case STATE_W4_SERVICE: 138ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Unexpected packet in STATE_W4_SERVICE"); 139ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito break; 140ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito case STATE_XFER: 141ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito // Regular packet data 142ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito sendDataToServiceLocked(mActiveService, data); 143ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito break; 144ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 145ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 146ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 147ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 148ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito public void onHostEmulationDeactivated() { 149ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "notifyHostEmulationDeactivated"); 150ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito synchronized (mLock) { 151ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito sendDeactivateToActiveServiceLocked(HostNfcFService.DEACTIVATION_LINK_LOSS); 152ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mActiveService = null; 153ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mActiveServiceName = null; 154ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito unbindServiceIfNeededLocked(); 155ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mState = STATE_IDLE; 156ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 157ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 158ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 159ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito public void onNfcDisabled() { 160ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito synchronized (mLock) { 161ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito sendDeactivateToActiveServiceLocked(HostNfcFService.DEACTIVATION_LINK_LOSS); 162ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mEnabledFgServiceName = null; 163ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mActiveService = null; 164ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mActiveServiceName = null; 165ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito unbindServiceIfNeededLocked(); 166ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mState = STATE_IDLE; 167ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 168ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 169ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 170ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito public void onUserSwitched() { 171ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito synchronized (mLock) { 172ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito sendDeactivateToActiveServiceLocked(HostNfcFService.DEACTIVATION_LINK_LOSS); 173ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mEnabledFgServiceName = null; 174ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mActiveService = null; 175ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mActiveServiceName = null; 176ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito unbindServiceIfNeededLocked(); 177ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mState = STATE_IDLE; 178ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 179ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 180ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 181ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito void sendDataToServiceLocked(Messenger service, byte[] data) { 182ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "sendDataToServiceLocked"); 183ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) { 184ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "service: " + 185ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito (service != null ? service.toString() : "null")); 186ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "mActiveService: " + 187ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito (mActiveService != null ? mActiveService.toString() : "null")); 188ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 189ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (service != mActiveService) { 190ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito sendDeactivateToActiveServiceLocked(HostNfcFService.DEACTIVATION_LINK_LOSS); 191ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mActiveService = service; 192ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mActiveServiceName = mServiceName; 193ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 194ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Message msg = Message.obtain(null, HostNfcFService.MSG_COMMAND_PACKET); 195ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Bundle dataBundle = new Bundle(); 196ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito dataBundle.putByteArray("data", data); 197ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito msg.setData(dataBundle); 198ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito msg.replyTo = mMessenger; 199ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito try { 200ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Sending data to service"); 201ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "data: " + getByteDump(data)); 202ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mActiveService.send(msg); 203ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } catch (RemoteException e) { 204ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.e(TAG, "Remote service has died, dropping packet"); 205ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 206ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 207ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 208ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito void sendDeactivateToActiveServiceLocked(int reason) { 209ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "sendDeactivateToActiveServiceLocked"); 210ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (mActiveService == null) return; 211ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Message msg = Message.obtain(null, HostNfcFService.MSG_DEACTIVATED); 212ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito msg.arg1 = reason; 213ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito try { 214ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mActiveService.send(msg); 215ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } catch (RemoteException e) { 216ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito // Don't care 217ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 218ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 219ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 220ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Messenger bindServiceIfNeededLocked(ComponentName service) { 221ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "bindServiceIfNeededLocked"); 222ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (mServiceBound && mServiceName.equals(service)) { 223ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Service already bound."); 224ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return mService; 225ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } else { 226ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Binding to service " + service); 227ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito unbindServiceIfNeededLocked(); 228ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Intent bindIntent = new Intent(HostNfcFService.SERVICE_INTERFACE); 229ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito bindIntent.setComponent(service); 230ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (mContext.bindServiceAsUser(bindIntent, mConnection, 231ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) { 232ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } else { 233ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.e(TAG, "Could not bind service."); 234ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 235ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return null; 236ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 237ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 238ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 239ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito void unbindServiceIfNeededLocked() { 240ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "unbindServiceIfNeededLocked"); 241ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (mServiceBound) { 242ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Unbinding from service " + mServiceName); 243ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mContext.unbindService(mConnection); 244ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mServiceBound = false; 245ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mService = null; 246ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mServiceName = null; 247ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 248ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 249ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 250ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito String findNfcid2(byte[] data) { 251ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "findNfcid2"); 252ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (data == null || data.length < MINIMUM_NFCF_PACKET_LENGTH) { 253ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "Data size too small"); 254ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return null; 255ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 256ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito int nfcid2Offset = 2; 257ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return bytesToString(data, nfcid2Offset, NFCID2_LENGTH); 258ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 259ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 260ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito private ServiceConnection mConnection = new ServiceConnection() { 261ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito @Override 262ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito public void onServiceConnected(ComponentName name, IBinder service) { 263ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito synchronized (mLock) { 264ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mService = new Messenger(service); 265ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mServiceBound = true; 266ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mServiceName = name; 267ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Service bound"); 268ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mState = STATE_XFER; 269ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito // Send pending packet 270ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (mPendingPacket != null) { 271ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito sendDataToServiceLocked(mService, mPendingPacket); 272ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mPendingPacket = null; 273ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 274ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 275ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 276ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 277ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito @Override 278ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito public void onServiceDisconnected(ComponentName name) { 279ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito synchronized (mLock) { 280ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Service unbound"); 281ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mService = null; 282ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mServiceBound = false; 283ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito mServiceName = null; 284ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 285ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 286ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito }; 287ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 288ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito class MessageHandler extends Handler { 289ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito @Override 290ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito public void handleMessage(Message msg) { 291ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito synchronized(mLock) { 292ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (mActiveService == null) { 293ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Dropping service response message; service no longer active."); 294ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return; 295ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } else if (!msg.replyTo.getBinder().equals(mActiveService.getBinder())) { 296ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Dropping service response message; service no longer bound."); 297ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return; 298ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 299ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 300ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (msg.what == HostNfcFService.MSG_RESPONSE_PACKET) { 301ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Bundle dataBundle = msg.getData(); 302ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (dataBundle == null) { 303ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return; 304ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 305ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito byte[] data = dataBundle.getByteArray("data"); 306ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (data == null) { 307ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return; 308ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 309ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (data.length == 0) { 310ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.e(TAG, "Invalid response packet"); 311ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return; 312ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 313ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (data.length != (data[0] & 0xff)) { 314ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.e(TAG, "Invalid response packet"); 315ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return; 316ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 317ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito int state; 318ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito synchronized(mLock) { 319ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito state = mState; 320ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 321ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (state == STATE_XFER) { 322ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Sending data"); 323ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (DBG) Log.d(TAG, "data:" + getByteDump(data)); 324ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito NfcService.getInstance().sendData(data); 325ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } else { 326ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito Log.d(TAG, "Dropping data, wrong state " + Integer.toString(state)); 327ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 328ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 329ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 330ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 331ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 332ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito static String bytesToString(byte[] bytes, int offset, int length) { 333ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito final char[] hexChars = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; 334ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito char[] chars = new char[length * 2]; 335ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito int byteValue; 336ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito for (int j = 0; j < length; j++) { 337ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito byteValue = bytes[offset + j] & 0xFF; 338ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito chars[j * 2] = hexChars[byteValue >>> 4]; 339ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito chars[j * 2 + 1] = hexChars[byteValue & 0x0F]; 340ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 341ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return new String(chars); 342ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 343ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 344ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito private String getByteDump(final byte[] cmd) { 345ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito StringBuffer str = new StringBuffer(""); 346ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito int letters = 8; 347ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito int i = 0; 348ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 349ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (cmd == null) { 350ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito str.append(" null\n"); 351ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return str.toString(); 352ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 353ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 354ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito for (; i < cmd.length; i++) { 355ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito str.append(String.format(" %02X", cmd[i])); 356ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if ((i % letters == letters - 1) || (i + 1 == cmd.length)) { 357ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito str.append("\n"); 358ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 359ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 360ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 361ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito return str.toString(); 362ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 363ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito 364ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 365ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito pw.println("Bound services: "); 366ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito if (mServiceBound) { 367ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito pw.println(" service: " + mServiceName); 368ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 369ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito } 370ecb8d7bbd1a44cd3edbcb6c5d903fc8d9a625d70Yoshinobu Ito} 371