VoiceInteractionManagerService.java revision 8cf8f71644643601fe8c3e9538fd00412b1ae8b1
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.voiceinteraction;
18
19import android.Manifest;
20import android.app.ActivityManager;
21import android.app.AppGlobals;
22import android.content.ComponentName;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.pm.ApplicationInfo;
27import android.content.pm.IPackageManager;
28import android.content.pm.PackageManager;
29import android.content.pm.ResolveInfo;
30import android.content.pm.ServiceInfo;
31import android.database.ContentObserver;
32import android.hardware.soundtrigger.IRecognitionStatusCallback;
33import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
34import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
35import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
36import android.os.Binder;
37import android.os.Bundle;
38import android.os.Handler;
39import android.os.IBinder;
40import android.os.Parcel;
41import android.os.RemoteException;
42import android.os.SystemProperties;
43import android.os.UserHandle;
44import android.provider.Settings;
45import android.service.voice.IVoiceInteractionService;
46import android.service.voice.IVoiceInteractionSession;
47import android.service.voice.VoiceInteractionService;
48import android.service.voice.VoiceInteractionServiceInfo;
49import android.speech.RecognitionService;
50import android.text.TextUtils;
51import android.util.Slog;
52
53import com.android.internal.app.IVoiceInteractionManagerService;
54import com.android.internal.app.IVoiceInteractor;
55import com.android.internal.content.PackageMonitor;
56import com.android.internal.os.BackgroundThread;
57import com.android.server.SystemService;
58import com.android.server.UiThread;
59
60import java.io.FileDescriptor;
61import java.io.PrintWriter;
62import java.util.List;
63
64/**
65 * SystemService that publishes an IVoiceInteractionManagerService.
66 */
67public class VoiceInteractionManagerService extends SystemService {
68    static final String TAG = "VoiceInteractionManagerService";
69    static final boolean DEBUG = false;
70
71    final Context mContext;
72    final ContentResolver mResolver;
73    final DatabaseHelper mDbHelper;
74    final SoundTriggerHelper mSoundTriggerHelper;
75
76    public VoiceInteractionManagerService(Context context) {
77        super(context);
78        mContext = context;
79        mResolver = context.getContentResolver();
80        mDbHelper = new DatabaseHelper(context);
81        mSoundTriggerHelper = new SoundTriggerHelper(context);
82    }
83
84    @Override
85    public void onStart() {
86        publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
87    }
88
89    @Override
90    public void onBootPhase(int phase) {
91        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
92            mServiceStub.systemRunning(isSafeMode());
93        }
94    }
95
96    @Override
97    public void onStartUser(int userHandle) {
98        mServiceStub.initForUser(userHandle);
99    }
100
101    @Override
102    public void onSwitchUser(int userHandle) {
103        mServiceStub.switchUser(userHandle);
104    }
105
106    // implementation entry point and binder service
107    private final VoiceInteractionManagerServiceStub mServiceStub
108            = new VoiceInteractionManagerServiceStub();
109
110    class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
111
112        VoiceInteractionManagerServiceImpl mImpl;
113
114        private boolean mSafeMode;
115        private int mCurUser;
116
117        @Override
118        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
119                throws RemoteException {
120            try {
121                return super.onTransact(code, data, reply, flags);
122            } catch (RuntimeException e) {
123                // The activity manager only throws security exceptions, so let's
124                // log all others.
125                if (!(e instanceof SecurityException)) {
126                    Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e);
127                }
128                throw e;
129            }
130        }
131
132        public void initForUser(int userHandle) {
133            if (DEBUG) Slog.i(TAG, "initForUser user=" + userHandle);
134            String curInteractorStr = Settings.Secure.getStringForUser(
135                    mContext.getContentResolver(),
136                    Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
137            ComponentName curRecognizer = getCurRecognizer(userHandle);
138            VoiceInteractionServiceInfo curInteractorInfo = null;
139            if (curInteractorStr == null && curRecognizer != null) {
140                // If there is no interactor setting, that means we are upgrading
141                // from an older platform version.  If the current recognizer is not
142                // set or matches the preferred recognizer, then we want to upgrade
143                // the user to have the default voice interaction service enabled.
144                curInteractorInfo = findAvailInteractor(userHandle, curRecognizer);
145                if (curInteractorInfo != null) {
146                    // Looks good!  We'll apply this one.  To make it happen, we clear the
147                    // recognizer so that we don't think we have anything set and will
148                    // re-apply the settings.
149                    curRecognizer = null;
150                }
151            }
152
153            if (curRecognizer != null) {
154                // If we already have at least a recognizer, then we probably want to
155                // leave things as they are...  unless something has disappeared.
156                IPackageManager pm = AppGlobals.getPackageManager();
157                ServiceInfo interactorInfo = null;
158                ServiceInfo recognizerInfo = null;
159                ComponentName curInteractor = !TextUtils.isEmpty(curInteractorStr)
160                        ? ComponentName.unflattenFromString(curInteractorStr) : null;
161                try {
162                    recognizerInfo = pm.getServiceInfo(curRecognizer, 0, userHandle);
163                    if (curInteractor != null) {
164                        interactorInfo = pm.getServiceInfo(curInteractor, 0, userHandle);
165                    }
166                } catch (RemoteException e) {
167                }
168                // If the apps for the currently set components still exist, then all is okay.
169                if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) {
170                    return;
171                }
172            }
173
174            // Initializing settings, look for an interactor first.
175            if (curInteractorInfo == null) {
176                curInteractorInfo = findAvailInteractor(userHandle, null);
177            }
178            if (curInteractorInfo != null) {
179                // Eventually it will be an error to not specify this.
180                setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName,
181                        curInteractorInfo.getServiceInfo().name), userHandle);
182                if (curInteractorInfo.getRecognitionService() != null) {
183                    setCurRecognizer(
184                            new ComponentName(curInteractorInfo.getServiceInfo().packageName,
185                                    curInteractorInfo.getRecognitionService()), userHandle);
186                    return;
187                }
188            }
189
190            // No voice interactor, we'll just set up a simple recognizer.
191            curRecognizer = findAvailRecognizer(null, userHandle);
192            if (curRecognizer != null) {
193                if (curInteractorInfo == null) {
194                    setCurInteractor(null, userHandle);
195                }
196                setCurRecognizer(curRecognizer, userHandle);
197            }
198        }
199
200        public void systemRunning(boolean safeMode) {
201            mSafeMode = safeMode;
202
203            mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(),
204                    UserHandle.ALL, true);
205            new SettingsObserver(UiThread.getHandler());
206
207            synchronized (this) {
208                mCurUser = ActivityManager.getCurrentUser();
209                switchImplementationIfNeededLocked(false);
210            }
211        }
212
213        public void switchUser(int userHandle) {
214            synchronized (this) {
215                mCurUser = userHandle;
216                switchImplementationIfNeededLocked(false);
217            }
218        }
219
220        void switchImplementationIfNeededLocked(boolean force) {
221            if (!mSafeMode) {
222                String curService = Settings.Secure.getStringForUser(
223                        mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
224                ComponentName serviceComponent = null;
225                if (curService != null && !curService.isEmpty()) {
226                    try {
227                        serviceComponent = ComponentName.unflattenFromString(curService);
228                    } catch (RuntimeException e) {
229                        Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
230                        serviceComponent = null;
231                    }
232                }
233                if (force || mImpl == null || mImpl.mUser != mCurUser
234                        || !mImpl.mComponent.equals(serviceComponent)) {
235                    mSoundTriggerHelper.stopAllRecognitions();
236                    if (mImpl != null) {
237                        mImpl.shutdownLocked();
238                    }
239                    if (serviceComponent != null) {
240                        mImpl = new VoiceInteractionManagerServiceImpl(mContext,
241                                UiThread.getHandler(), this, mCurUser, serviceComponent);
242                        mImpl.startLocked();
243                    } else {
244                        mImpl = null;
245                    }
246                }
247            }
248        }
249
250        VoiceInteractionServiceInfo findAvailInteractor(int userHandle, ComponentName recognizer) {
251            List<ResolveInfo> available =
252                    mContext.getPackageManager().queryIntentServicesAsUser(
253                            new Intent(VoiceInteractionService.SERVICE_INTERFACE), 0, userHandle);
254            int numAvailable = available.size();
255
256            if (numAvailable == 0) {
257                Slog.w(TAG, "no available voice interaction services found for user " + userHandle);
258                return null;
259            } else {
260                // Find first system package.  We never want to allow third party services to
261                // be automatically selected, because those require approval of the user.
262                VoiceInteractionServiceInfo foundInfo = null;
263                for (int i=0; i<numAvailable; i++) {
264                    ServiceInfo cur = available.get(i).serviceInfo;
265                    if ((cur.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
266                        ComponentName comp = new ComponentName(cur.packageName, cur.name);
267                        try {
268                            VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo(
269                                    mContext.getPackageManager(), comp, userHandle);
270                            if (info.getParseError() == null) {
271                                if (recognizer == null || info.getServiceInfo().packageName.equals(
272                                        recognizer.getPackageName())) {
273                                    if (foundInfo == null) {
274                                        foundInfo = info;
275                                    } else {
276                                        Slog.w(TAG, "More than one voice interaction service, "
277                                                + "picking first "
278                                                + new ComponentName(
279                                                        foundInfo.getServiceInfo().packageName,
280                                                        foundInfo.getServiceInfo().name)
281                                                + " over "
282                                                + new ComponentName(cur.packageName, cur.name));
283                                    }
284                                }
285                            } else {
286                                Slog.w(TAG, "Bad interaction service " + comp + ": "
287                                        + info.getParseError());
288                            }
289                        } catch (PackageManager.NameNotFoundException e) {
290                            Slog.w(TAG, "Failure looking up interaction service " + comp);
291                        } catch (RemoteException e) {
292                        }
293                    }
294                }
295
296                return foundInfo;
297            }
298        }
299
300        ComponentName getCurInteractor(int userHandle) {
301            String curInteractor = Settings.Secure.getStringForUser(
302                    mContext.getContentResolver(),
303                    Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
304            if (TextUtils.isEmpty(curInteractor)) {
305                return null;
306            }
307            if (DEBUG) Slog.i(TAG, "getCurInteractor curInteractor=" + curInteractor
308                    + " user=" + userHandle);
309            return ComponentName.unflattenFromString(curInteractor);
310        }
311
312        void setCurInteractor(ComponentName comp, int userHandle) {
313            Settings.Secure.putStringForUser(mContext.getContentResolver(),
314                    Settings.Secure.VOICE_INTERACTION_SERVICE,
315                    comp != null ? comp.flattenToShortString() : "", userHandle);
316            if (DEBUG) Slog.i(TAG, "setCurInteractor comp=" + comp
317                    + " user=" + userHandle);
318        }
319
320        ComponentName findAvailRecognizer(String prefPackage, int userHandle) {
321            List<ResolveInfo> available =
322                    mContext.getPackageManager().queryIntentServicesAsUser(
323                            new Intent(RecognitionService.SERVICE_INTERFACE), 0, userHandle);
324            int numAvailable = available.size();
325
326            if (numAvailable == 0) {
327                Slog.w(TAG, "no available voice recognition services found for user " + userHandle);
328                return null;
329            } else {
330                if (prefPackage != null) {
331                    for (int i=0; i<numAvailable; i++) {
332                        ServiceInfo serviceInfo = available.get(i).serviceInfo;
333                        if (prefPackage.equals(serviceInfo.packageName)) {
334                            return new ComponentName(serviceInfo.packageName, serviceInfo.name);
335                        }
336                    }
337                }
338                if (numAvailable > 1) {
339                    Slog.w(TAG, "more than one voice recognition service found, picking first");
340                }
341
342                ServiceInfo serviceInfo = available.get(0).serviceInfo;
343                return new ComponentName(serviceInfo.packageName, serviceInfo.name);
344            }
345        }
346
347        ComponentName getCurRecognizer(int userHandle) {
348            String curRecognizer = Settings.Secure.getStringForUser(
349                    mContext.getContentResolver(),
350                    Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle);
351            if (TextUtils.isEmpty(curRecognizer)) {
352                return null;
353            }
354            if (DEBUG) Slog.i(TAG, "getCurRecognizer curRecognizer=" + curRecognizer
355                    + " user=" + userHandle);
356            return ComponentName.unflattenFromString(curRecognizer);
357        }
358
359        void setCurRecognizer(ComponentName comp, int userHandle) {
360            Settings.Secure.putStringForUser(mContext.getContentResolver(),
361                    Settings.Secure.VOICE_RECOGNITION_SERVICE,
362                    comp != null ? comp.flattenToShortString() : "", userHandle);
363            if (DEBUG) Slog.i(TAG, "setCurRecognizer comp=" + comp
364                    + " user=" + userHandle);
365        }
366
367        @Override
368        public void startSession(IVoiceInteractionService service, Bundle args) {
369            synchronized (this) {
370                if (mImpl == null || mImpl.mService == null
371                        || service.asBinder() != mImpl.mService.asBinder()) {
372                    throw new SecurityException(
373                            "Caller is not the current voice interaction service");
374                }
375                final int callingPid = Binder.getCallingPid();
376                final int callingUid = Binder.getCallingUid();
377                final long caller = Binder.clearCallingIdentity();
378                try {
379                    mImpl.startSessionLocked(callingPid, callingUid, args);
380                } finally {
381                    Binder.restoreCallingIdentity(caller);
382                }
383            }
384        }
385
386        @Override
387        public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
388                IVoiceInteractor interactor) {
389            synchronized (this) {
390                if (mImpl == null) {
391                    throw new SecurityException(
392                            "deliverNewSession without running voice interaction service");
393                }
394                final int callingPid = Binder.getCallingPid();
395                final int callingUid = Binder.getCallingUid();
396                final long caller = Binder.clearCallingIdentity();
397                try {
398                    return mImpl.deliverNewSessionLocked(callingPid, callingUid, token, session,
399                            interactor);
400                } finally {
401                    Binder.restoreCallingIdentity(caller);
402                }
403            }
404        }
405
406        @Override
407        public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
408            synchronized (this) {
409                if (mImpl == null) {
410                    Slog.w(TAG, "startVoiceActivity without running voice interaction service");
411                    return ActivityManager.START_CANCELED;
412                }
413                final int callingPid = Binder.getCallingPid();
414                final int callingUid = Binder.getCallingUid();
415                final long caller = Binder.clearCallingIdentity();
416                if (!SystemProperties.getBoolean("persist.test.voice_interaction", false)) {
417                    throw new SecurityException("Voice interaction not supported");
418                }
419                try {
420                    return mImpl.startVoiceActivityLocked(callingPid, callingUid, token,
421                            intent, resolvedType);
422                } finally {
423                    Binder.restoreCallingIdentity(caller);
424                }
425            }
426        }
427
428        @Override
429        public void finish(IBinder token) {
430            synchronized (this) {
431                if (mImpl == null) {
432                    Slog.w(TAG, "finish without running voice interaction service");
433                    return;
434                }
435                final int callingPid = Binder.getCallingPid();
436                final int callingUid = Binder.getCallingUid();
437                final long caller = Binder.clearCallingIdentity();
438                try {
439                    mImpl.finishLocked(callingPid, callingUid, token);
440                } finally {
441                    Binder.restoreCallingIdentity(caller);
442                }
443            }
444        }
445
446        //----------------- Model management APIs --------------------------------//
447
448        @Override
449        public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
450            synchronized (this) {
451                if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
452                        != PackageManager.PERMISSION_GRANTED) {
453                    throw new SecurityException("Caller does not hold the permission "
454                            + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
455                }
456            }
457
458            if (bcp47Locale == null) {
459                throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel");
460            }
461
462            final int callingUid = UserHandle.getCallingUserId();
463            final long caller = Binder.clearCallingIdentity();
464            try {
465                return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
466            } finally {
467                Binder.restoreCallingIdentity(caller);
468            }
469        }
470
471        @Override
472        public int updateKeyphraseSoundModel(KeyphraseSoundModel model) {
473            synchronized (this) {
474                if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
475                        != PackageManager.PERMISSION_GRANTED) {
476                    throw new SecurityException("Caller does not hold the permission "
477                            + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
478                }
479                if (model == null) {
480                    throw new IllegalArgumentException("Model must not be null");
481                }
482            }
483
484            final long caller = Binder.clearCallingIdentity();
485            try {
486                if (mDbHelper.updateKeyphraseSoundModel(model)) {
487                    synchronized (this) {
488                        // Notify the voice interaction service of a change in sound models.
489                        if (mImpl != null && mImpl.mService != null) {
490                            mImpl.notifySoundModelsChangedLocked();
491                        }
492                    }
493                    return SoundTriggerHelper.STATUS_OK;
494                } else {
495                    return SoundTriggerHelper.STATUS_ERROR;
496                }
497            } finally {
498                Binder.restoreCallingIdentity(caller);
499            }
500        }
501
502        @Override
503        public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
504            synchronized (this) {
505                if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
506                        != PackageManager.PERMISSION_GRANTED) {
507                    throw new SecurityException("Caller does not hold the permission "
508                            + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
509                }
510            }
511
512            if (bcp47Locale == null) {
513                throw new IllegalArgumentException(
514                        "Illegal argument(s) in deleteKeyphraseSoundModel");
515            }
516
517            final int callingUid = UserHandle.getCallingUserId();
518            final long caller = Binder.clearCallingIdentity();
519            boolean deleted = false;
520            try {
521                deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
522                return deleted ? SoundTriggerHelper.STATUS_OK : SoundTriggerHelper.STATUS_ERROR;
523            } finally {
524                if (deleted) {
525                    synchronized (this) {
526                        // Notify the voice interaction service of a change in sound models.
527                        if (mImpl != null && mImpl.mService != null) {
528                            mImpl.notifySoundModelsChangedLocked();
529                        }
530                    }
531                }
532                Binder.restoreCallingIdentity(caller);
533            }
534        }
535
536        //----------------- SoundTrigger APIs --------------------------------//
537        @Override
538        public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId,
539                String bcp47Locale) {
540            synchronized (this) {
541                if (mImpl == null || mImpl.mService == null
542                        || service.asBinder() != mImpl.mService.asBinder()) {
543                    throw new SecurityException(
544                            "Caller is not the current voice interaction service");
545                }
546            }
547
548            if (bcp47Locale == null) {
549                throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase");
550            }
551
552            final int callingUid = UserHandle.getCallingUserId();
553            final long caller = Binder.clearCallingIdentity();
554            try {
555                KeyphraseSoundModel model =
556                        mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
557                return model != null;
558            } finally {
559                Binder.restoreCallingIdentity(caller);
560            }
561        }
562
563        @Override
564        public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) {
565            // Allow the call if this is the current voice interaction service.
566            synchronized (this) {
567                if (mImpl == null || mImpl.mService == null
568                        || service == null || service.asBinder() != mImpl.mService.asBinder()) {
569                    throw new SecurityException(
570                            "Caller is not the current voice interaction service");
571                }
572
573                final long caller = Binder.clearCallingIdentity();
574                try {
575                    return mSoundTriggerHelper.moduleProperties;
576                } finally {
577                    Binder.restoreCallingIdentity(caller);
578                }
579            }
580        }
581
582        @Override
583        public int startRecognition(IVoiceInteractionService service, int keyphraseId,
584                String bcp47Locale, IRecognitionStatusCallback callback,
585                RecognitionConfig recognitionConfig) {
586            // Allow the call if this is the current voice interaction service.
587            synchronized (this) {
588                if (mImpl == null || mImpl.mService == null
589                        || service == null || service.asBinder() != mImpl.mService.asBinder()) {
590                    throw new SecurityException(
591                            "Caller is not the current voice interaction service");
592                }
593
594                if (callback == null || recognitionConfig == null || bcp47Locale == null) {
595                    throw new IllegalArgumentException("Illegal argument(s) in startRecognition");
596                }
597            }
598
599            int callingUid = UserHandle.getCallingUserId();
600            final long caller = Binder.clearCallingIdentity();
601            try {
602                KeyphraseSoundModel soundModel =
603                        mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
604                if (soundModel == null
605                        || soundModel.uuid == null
606                        || soundModel.keyphrases == null) {
607                    Slog.w(TAG, "No matching sound model found in startRecognition");
608                    return SoundTriggerHelper.STATUS_ERROR;
609                } else {
610                    return mSoundTriggerHelper.startRecognition(
611                            keyphraseId, soundModel, callback, recognitionConfig);
612                }
613            } finally {
614                Binder.restoreCallingIdentity(caller);
615            }
616        }
617
618        @Override
619        public int stopRecognition(IVoiceInteractionService service, int keyphraseId,
620                IRecognitionStatusCallback callback) {
621            // Allow the call if this is the current voice interaction service.
622            synchronized (this) {
623                if (mImpl == null || mImpl.mService == null
624                        || service == null || service.asBinder() != mImpl.mService.asBinder()) {
625                    throw new SecurityException(
626                            "Caller is not the current voice interaction service");
627                }
628            }
629
630            final long caller = Binder.clearCallingIdentity();
631            try {
632                return mSoundTriggerHelper.stopRecognition(keyphraseId, callback);
633            } finally {
634                Binder.restoreCallingIdentity(caller);
635            }
636        }
637
638        @Override
639        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
640            if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
641                    != PackageManager.PERMISSION_GRANTED) {
642                pw.println("Permission Denial: can't dump PowerManager from from pid="
643                        + Binder.getCallingPid()
644                        + ", uid=" + Binder.getCallingUid());
645                return;
646            }
647            synchronized (this) {
648                pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n");
649                if (mImpl == null) {
650                    pw.println("  (No active implementation)");
651                    return;
652                }
653                mImpl.dumpLocked(fd, pw, args);
654            }
655            mSoundTriggerHelper.dump(fd, pw, args);
656        }
657
658        class SettingsObserver extends ContentObserver {
659            SettingsObserver(Handler handler) {
660                super(handler);
661                ContentResolver resolver = mContext.getContentResolver();
662                resolver.registerContentObserver(Settings.Secure.getUriFor(
663                        Settings.Secure.VOICE_INTERACTION_SERVICE), false, this);
664            }
665
666            @Override public void onChange(boolean selfChange) {
667                synchronized (VoiceInteractionManagerServiceStub.this) {
668                    switchImplementationIfNeededLocked(false);
669                }
670            }
671        }
672
673        PackageMonitor mPackageMonitor = new PackageMonitor() {
674            @Override
675            public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
676                return super.onHandleForceStop(intent, packages, uid, doit);
677            }
678
679            @Override
680            public void onHandleUserStop(Intent intent, int userHandle) {
681            }
682
683            @Override
684            public void onSomePackagesChanged() {
685                int userHandle = getChangingUserId();
686                if (DEBUG) Slog.i(TAG, "onSomePackagesChanged user=" + userHandle);
687
688                ComponentName curInteractor = getCurInteractor(userHandle);
689                ComponentName curRecognizer = getCurRecognizer(userHandle);
690                if (curRecognizer == null) {
691                    // Could a new recognizer appear when we don't have one pre-installed?
692                    if (anyPackagesAppearing()) {
693                        curRecognizer = findAvailRecognizer(null, userHandle);
694                        if (curRecognizer != null) {
695                            setCurRecognizer(curRecognizer, userHandle);
696                        }
697                    }
698                    return;
699                }
700
701                if (curInteractor != null) {
702                    int change = isPackageDisappearing(curInteractor.getPackageName());
703                    if (change == PACKAGE_PERMANENT_CHANGE) {
704                        // The currently set interactor is permanently gone; fall back to
705                        // the default config.
706                        setCurInteractor(null, userHandle);
707                        setCurRecognizer(null, userHandle);
708                        initForUser(userHandle);
709                        return;
710                    }
711
712                    change = isPackageAppearing(curInteractor.getPackageName());
713                    if (change != PACKAGE_UNCHANGED) {
714                        // If current interactor is now appearing, for any reason, then
715                        // restart our connection with it.
716                        if (mImpl != null && curInteractor.getPackageName().equals(
717                                mImpl.mComponent.getPackageName())) {
718                            switchImplementationIfNeededLocked(true);
719                        }
720                    }
721                    return;
722                }
723
724                // There is no interactor, so just deal with a simple recognizer.
725                int change = isPackageDisappearing(curRecognizer.getPackageName());
726                if (change == PACKAGE_PERMANENT_CHANGE
727                        || change == PACKAGE_TEMPORARY_CHANGE) {
728                    setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
729
730                } else if (isPackageModified(curRecognizer.getPackageName())) {
731                    setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(),
732                            userHandle), userHandle);
733                }
734            }
735        };
736    }
737}
738