OSDN Git Service

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