15c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock/*
25c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * Copyright (C) 2013 The Android Open Source Project
35c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock *
45c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * Licensed under the Apache License, Version 2.0 (the "License");
55c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * you may not use this file except in compliance with the License.
65c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * You may obtain a copy of the License at
75c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock *
85c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock *      http://www.apache.org/licenses/LICENSE-2.0
95c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock *
105c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * Unless required by applicable law or agreed to in writing, software
115c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * distributed under the License is distributed on an "AS IS" BASIS,
125c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * See the License for the specific language governing permissions and
145c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * limitations under the License.
155c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock */
165c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
175c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockpackage com.android.systemui.statusbar;
185c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
195c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.content.BroadcastReceiver;
205c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.content.ComponentName;
215c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.content.ContentResolver;
225c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.content.Context;
235c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.content.Intent;
245c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.content.IntentFilter;
255c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.content.ServiceConnection;
265c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.content.pm.PackageManager;
275c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.database.ContentObserver;
285c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.net.Uri;
295c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.os.Bundle;
305c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.os.Handler;
315c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.os.IBinder;
325c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.os.Message;
335c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.os.RemoteException;
345c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.os.UserHandle;
355c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.provider.Settings;
365c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport android.util.Log;
375c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
385c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockimport java.util.Arrays;
395c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
405c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock/**
415c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * Manages a persistent connection to a service component defined in a secure setting.
425c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock *
435c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * <p>If a valid service component is specified in the secure setting, starts it up and keeps it
445c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * running; handling setting changes, package updates, component disabling, and unexpected
455c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * process termination.
465c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock *
475c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock * <p>Clients can listen for important events using the supplied {@link Callbacks}.
485c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock */
495c4541246c6a70f53552423dc35940386788bd5fJohn Spurlockpublic class ServiceMonitor {
505c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private static final int RECHECK_DELAY = 2000;
515c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private static final int WAIT_FOR_STOP = 500;
525c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
535c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    public interface Callbacks {
545c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        /** The service does not exist or failed to bind */
555c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        void onNoService();
565c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        /** The service is about to start, this is a chance to perform cleanup and
575c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock         * delay the start if necessary */
585c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        long onServiceStartAttempt();
595c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
605c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
615c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    // internal handler + messages used to serialize access to internal state
625c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    public static final int MSG_START_SERVICE = 1;
635c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    public static final int MSG_CONTINUE_START_SERVICE = 2;
645c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    public static final int MSG_STOP_SERVICE = 3;
655c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    public static final int MSG_PACKAGE_INTENT = 4;
665c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    public static final int MSG_CHECK_BOUND = 5;
675c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    public static final int MSG_SERVICE_DISCONNECTED = 6;
685c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
695c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private final Handler mHandler = new Handler() {
705c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        public void handleMessage(Message msg) {
715c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            switch(msg.what) {
725c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                case MSG_START_SERVICE:
735c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    startService();
745c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    break;
755c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                case MSG_CONTINUE_START_SERVICE:
765c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    continueStartService();
775c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    break;
785c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                case MSG_STOP_SERVICE:
795c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    stopService();
805c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    break;
815c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                case MSG_PACKAGE_INTENT:
825c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    packageIntent((Intent)msg.obj);
835c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    break;
845c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                case MSG_CHECK_BOUND:
855c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    checkBound();
865c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    break;
875c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                case MSG_SERVICE_DISCONNECTED:
885c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    serviceDisconnected((ComponentName)msg.obj);
895c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    break;
905c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            }
915c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
925c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    };
935c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
945c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private final ContentObserver mSettingObserver = new ContentObserver(mHandler) {
955c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        public void onChange(boolean selfChange) {
965c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            onChange(selfChange, null);
975c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
985c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
995c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        public void onChange(boolean selfChange, Uri uri) {
1005c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            if (mDebug) Log.d(mTag, "onChange selfChange=" + selfChange + " uri=" + uri);
1014db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock            ComponentName cn = getComponentNameFromSetting();
1024db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock            if (cn == null && mServiceName == null || cn != null && cn.equals(mServiceName)) {
1034db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock                if (mDebug) Log.d(mTag, "skipping no-op restart");
1044db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock                return;
1054db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock            }
1065c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            if (mBound) {
1075c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                mHandler.sendEmptyMessage(MSG_STOP_SERVICE);
1085c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            }
1095c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mHandler.sendEmptyMessageDelayed(MSG_START_SERVICE, WAIT_FOR_STOP);
1105c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
1115c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    };
1125c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1135c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private final class SC implements ServiceConnection, IBinder.DeathRecipient {
1145c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        private ComponentName mName;
1155c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        private IBinder mService;
1165c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1175c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        public void onServiceConnected(ComponentName name, IBinder service) {
1185c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            if (mDebug) Log.d(mTag, "onServiceConnected name=" + name + " service=" + service);
1195c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mName = name;
1205c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mService = service;
1215c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            try {
1225c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                service.linkToDeath(this, 0);
1235c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            } catch (RemoteException e) {
1245c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                Log.w(mTag, "Error linking to death", e);
1255c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            }
1265c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
1275c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1285c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        public void onServiceDisconnected(ComponentName name) {
1295c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            if (mDebug) Log.d(mTag, "onServiceDisconnected name=" + name);
1305c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            boolean unlinked = mService.unlinkToDeath(this, 0);
1315c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            if (mDebug) Log.d(mTag, "  unlinked=" + unlinked);
1325c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mHandler.sendMessage(mHandler.obtainMessage(MSG_SERVICE_DISCONNECTED, mName));
1335c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
1345c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1355c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        public void binderDied() {
1365c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            if (mDebug) Log.d(mTag, "binderDied");
1375c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mHandler.sendMessage(mHandler.obtainMessage(MSG_SERVICE_DISCONNECTED, mName));
1385c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
1395c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
1405c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1415c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1425c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        public void onReceive(Context context, Intent intent) {
1435c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            String pkg = intent.getData().getSchemeSpecificPart();
1445c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            if (mServiceName != null && mServiceName.getPackageName().equals(pkg)) {
1455c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                mHandler.sendMessage(mHandler.obtainMessage(MSG_PACKAGE_INTENT, intent));
1465c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            }
1475c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
1485c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    };
1495c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1505c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private final String mTag;
1515c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private final boolean mDebug;
1525c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1535c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private final Context mContext;
1545c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private final String mSettingKey;
1555c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private final Callbacks mCallbacks;
1565c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1575c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private ComponentName mServiceName;
1585c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private SC mServiceConnection;
1595c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private boolean mBound;
1605c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1615c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    public ServiceMonitor(String ownerTag, boolean debug,
1625c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            Context context, String settingKey, Callbacks callbacks) {
1635c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        mTag = ownerTag + ".ServiceMonitor";
1645c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        mDebug = debug;
1655c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        mContext = context;
1665c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        mSettingKey = settingKey;
1675c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        mCallbacks = callbacks;
1685c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
1695c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1705c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    public void start() {
1715c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        // listen for setting changes
1725c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        ContentResolver cr = mContext.getContentResolver();
1735c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        cr.registerContentObserver(Settings.Secure.getUriFor(mSettingKey),
1745c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                false /*notifyForDescendents*/, mSettingObserver, UserHandle.USER_ALL);
1755c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1765c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        // listen for package/component changes
1775c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        IntentFilter filter = new IntentFilter();
1785c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
1795c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1805c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        filter.addDataScheme("package");
1815c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        mContext.registerReceiver(mBroadcastReceiver, filter);
1825c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1835c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        mHandler.sendEmptyMessage(MSG_START_SERVICE);
1845c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
1855c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1864db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock    private ComponentName getComponentNameFromSetting() {
1874db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock        String cn = Settings.Secure.getStringForUser(mContext.getContentResolver(),
1884db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock                mSettingKey, UserHandle.USER_CURRENT);
1894db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock        return cn == null ? null : ComponentName.unflattenFromString(cn);
1904db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock    }
1914db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock
1925c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    // everything below is called on the handler
1935c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
1945c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private void packageIntent(Intent intent) {
1955c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (mDebug) Log.d(mTag, "packageIntent intent=" + intent
1965c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                + " extras=" + bundleToString(intent.getExtras()));
1975c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
1985c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mHandler.sendEmptyMessage(MSG_START_SERVICE);
1995c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        } else if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) {
2005c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            PackageManager pm = mContext.getPackageManager();
2015c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            boolean serviceEnabled =
2025c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    pm.getApplicationEnabledSetting(mServiceName.getPackageName())
2035c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                        != PackageManager.COMPONENT_ENABLED_STATE_DISABLED
2045c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                    && pm.getComponentEnabledSetting(mServiceName)
2055c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                        != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
2065c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            if (mBound && !serviceEnabled) {
2075c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                stopService();
2085c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                scheduleCheckBound();
2095c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            } else if (!mBound && serviceEnabled) {
2105c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                startService();
2115c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            }
2125c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
2135c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
2145c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
2155c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private void stopService() {
2165c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (mDebug) Log.d(mTag, "stopService");
2175c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        boolean stopped = mContext.stopService(new Intent().setComponent(mServiceName));
2185c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (mDebug) Log.d(mTag, "  stopped=" + stopped);
2195c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        mContext.unbindService(mServiceConnection);
2205c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        mBound = false;
2215c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
2225c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
2235c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private void startService() {
2244db614dbed10e74285eaa6d0e56c3e79a4afecc0John Spurlock        mServiceName = getComponentNameFromSetting();
2255c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (mDebug) Log.d(mTag, "startService mServiceName=" + mServiceName);
2265c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (mServiceName == null) {
2275c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mBound = false;
2285c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mCallbacks.onNoService();
2295c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        } else {
2305c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            long delay = mCallbacks.onServiceStartAttempt();
2315c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mHandler.sendEmptyMessageDelayed(MSG_CONTINUE_START_SERVICE, delay);
2325c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
2335c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
2345c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
2355c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private void continueStartService() {
2365c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (mDebug) Log.d(mTag, "continueStartService");
2375c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        Intent intent = new Intent().setComponent(mServiceName);
2385c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        try {
2395c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mServiceConnection = new SC();
2405c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mBound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
2415c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            if (mDebug) Log.d(mTag, "mBound: " + mBound);
2425c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        } catch (Throwable t) {
2435c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            Log.w(mTag, "Error binding to service: " + mServiceName, t);
2445c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
2455c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (!mBound) {
2465c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mCallbacks.onNoService();
2475c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
2485c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
2495c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
2505c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private void serviceDisconnected(ComponentName serviceName) {
2515c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (mDebug) Log.d(mTag, "serviceDisconnected serviceName=" + serviceName
2525c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock                + " mServiceName=" + mServiceName);
2535c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (serviceName.equals(mServiceName)) {
2545c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            mBound = false;
2555c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            scheduleCheckBound();
2565c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
2575c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
2585c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
2595c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private void checkBound() {
2605c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (mDebug) Log.d(mTag, "checkBound mBound=" + mBound);
2615c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (!mBound) {
2625c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            startService();
2635c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
2645c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
2655c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
2665c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private void scheduleCheckBound() {
2675c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        mHandler.removeMessages(MSG_CHECK_BOUND);
2685c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        mHandler.sendEmptyMessageDelayed(MSG_CHECK_BOUND, RECHECK_DELAY);
2695c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
2705c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock
2715c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    private static String bundleToString(Bundle bundle) {
2725c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        if (bundle == null) return null;
2735c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        StringBuilder sb = new StringBuilder('{');
2745c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        for (String key : bundle.keySet()) {
2755c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            if (sb.length() > 1) sb.append(',');
2765c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            Object v = bundle.get(key);
2775c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            v = (v instanceof String[]) ? Arrays.asList((String[]) v) : v;
2785c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock            sb.append(key).append('=').append(v);
2795c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        }
2805c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock        return sb.append('}').toString();
2815c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock    }
2825c4541246c6a70f53552423dc35940386788bd5fJohn Spurlock}
283