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.ActivityManagerInternal;
22 import android.app.AppGlobals;
23 import android.content.ComponentName;
24 import android.content.ContentResolver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.IPackageManager;
29 import android.content.pm.PackageManager;
30 import android.content.pm.PackageManagerInternal;
31 import android.content.pm.ResolveInfo;
32 import android.content.pm.ServiceInfo;
33 import android.content.res.Resources;
34 import android.database.ContentObserver;
35 import android.hardware.soundtrigger.IRecognitionStatusCallback;
36 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
37 import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
38 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
39 import android.os.Binder;
40 import android.os.Bundle;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.Parcel;
44 import android.os.RemoteException;
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.VoiceInteractionManagerInternal;
50 import android.service.voice.VoiceInteractionService;
51 import android.service.voice.VoiceInteractionServiceInfo;
52 import android.service.voice.VoiceInteractionSession;
53 import android.speech.RecognitionService;
54 import android.text.TextUtils;
55 import android.util.Log;
56 import android.util.Slog;
57 
58 import com.android.internal.app.IVoiceInteractionManagerService;
59 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
60 import com.android.internal.app.IVoiceInteractor;
61 import com.android.internal.content.PackageMonitor;
62 import com.android.internal.os.BackgroundThread;
63 import com.android.server.LocalServices;
64 import com.android.server.soundtrigger.SoundTriggerInternal;
65 import com.android.server.SystemService;
66 import com.android.server.UiThread;
67 
68 import java.io.FileDescriptor;
69 import java.io.PrintWriter;
70 import java.util.List;
71 import java.util.TreeSet;
72 
73 /**
74  * SystemService that publishes an IVoiceInteractionManagerService.
75  */
76 public class VoiceInteractionManagerService extends SystemService {
77     static final String TAG = "VoiceInteractionManagerService";
78     static final boolean DEBUG = false;
79 
80     final Context mContext;
81     final ContentResolver mResolver;
82     final DatabaseHelper mDbHelper;
83     final ActivityManagerInternal mAmInternal;
84     final TreeSet<Integer> mLoadedKeyphraseIds;
85     SoundTriggerInternal mSoundTriggerInternal;
86 
VoiceInteractionManagerService(Context context)87     public VoiceInteractionManagerService(Context context) {
88         super(context);
89         mContext = context;
90         mResolver = context.getContentResolver();
91         mDbHelper = new DatabaseHelper(context);
92         mServiceStub = new VoiceInteractionManagerServiceStub();
93         mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
94         mLoadedKeyphraseIds = new TreeSet<Integer>();
95 
96         PackageManagerInternal packageManagerInternal = LocalServices.getService(
97                 PackageManagerInternal.class);
98         packageManagerInternal.setVoiceInteractionPackagesProvider(
99                 new PackageManagerInternal.PackagesProvider() {
100             @Override
101             public String[] getPackages(int userId) {
102                 mServiceStub.initForUser(userId);
103                 ComponentName interactor = mServiceStub.getCurInteractor(userId);
104                 if (interactor != null) {
105                     return new String[] {interactor.getPackageName()};
106                 }
107                 return null;
108             }
109         });
110     }
111 
112     @Override
onStart()113     public void onStart() {
114         publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
115         publishLocalService(VoiceInteractionManagerInternal.class, new LocalService());
116     }
117 
118     @Override
onBootPhase(int phase)119     public void onBootPhase(int phase) {
120         if (PHASE_SYSTEM_SERVICES_READY == phase) {
121             mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
122         } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
123             mServiceStub.systemRunning(isSafeMode());
124         }
125     }
126 
127     @Override
onStartUser(int userHandle)128     public void onStartUser(int userHandle) {
129         mServiceStub.initForUser(userHandle);
130     }
131 
132     @Override
onUnlockUser(int userHandle)133     public void onUnlockUser(int userHandle) {
134         mServiceStub.initForUser(userHandle);
135         mServiceStub.switchImplementationIfNeeded(false);
136     }
137 
138     @Override
onSwitchUser(int userHandle)139     public void onSwitchUser(int userHandle) {
140         mServiceStub.switchUser(userHandle);
141     }
142 
143     class LocalService extends VoiceInteractionManagerInternal {
144         @Override
startLocalVoiceInteraction(IBinder callingActivity, Bundle options)145         public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
146             if (DEBUG) {
147                 Slog.i(TAG, "startLocalVoiceInteraction " + callingActivity);
148             }
149             VoiceInteractionManagerService.this.mServiceStub.startLocalVoiceInteraction(
150                     callingActivity, options);
151         }
152 
153         @Override
supportsLocalVoiceInteraction()154         public boolean supportsLocalVoiceInteraction() {
155             return VoiceInteractionManagerService.this.mServiceStub.supportsLocalVoiceInteraction();
156         }
157 
158         @Override
stopLocalVoiceInteraction(IBinder callingActivity)159         public void stopLocalVoiceInteraction(IBinder callingActivity) {
160             if (DEBUG) {
161                 Slog.i(TAG, "stopLocalVoiceInteraction " + callingActivity);
162             }
163             VoiceInteractionManagerService.this.mServiceStub.stopLocalVoiceInteraction(
164                     callingActivity);
165         }
166     }
167 
168     // implementation entry point and binder service
169     private final VoiceInteractionManagerServiceStub mServiceStub;
170 
171     class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
172 
173         VoiceInteractionManagerServiceImpl mImpl;
174 
175         private boolean mSafeMode;
176         private int mCurUser;
177         private final boolean mEnableService;
178 
VoiceInteractionManagerServiceStub()179         VoiceInteractionManagerServiceStub() {
180             mEnableService = shouldEnableService(mContext.getResources());
181         }
182 
183         // TODO: VI Make sure the caller is the current user or profile
startLocalVoiceInteraction(final IBinder token, Bundle options)184         void startLocalVoiceInteraction(final IBinder token, Bundle options) {
185             if (mImpl == null) return;
186 
187             final long caller = Binder.clearCallingIdentity();
188             try {
189                 mImpl.showSessionLocked(options,
190                         VoiceInteractionSession.SHOW_SOURCE_ACTIVITY,
191                         new IVoiceInteractionSessionShowCallback.Stub() {
192                             @Override
193                             public void onFailed() {
194                             }
195 
196                             @Override
197                             public void onShown() {
198                                 mAmInternal.onLocalVoiceInteractionStarted(token,
199                                         mImpl.mActiveSession.mSession,
200                                         mImpl.mActiveSession.mInteractor);
201                             }
202                         },
203                         token);
204             } finally {
205                 Binder.restoreCallingIdentity(caller);
206             }
207         }
208 
stopLocalVoiceInteraction(IBinder callingActivity)209         public void stopLocalVoiceInteraction(IBinder callingActivity) {
210             if (mImpl == null) return;
211 
212             final long caller = Binder.clearCallingIdentity();
213             try {
214                 mImpl.finishLocked(callingActivity, true);
215             } finally {
216                 Binder.restoreCallingIdentity(caller);
217             }
218         }
219 
supportsLocalVoiceInteraction()220         public boolean supportsLocalVoiceInteraction() {
221             if (mImpl == null) return false;
222 
223             return mImpl.supportsLocalVoiceInteraction();
224         }
225 
226         @Override
onTransact(int code, Parcel data, Parcel reply, int flags)227         public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
228                 throws RemoteException {
229             try {
230                 return super.onTransact(code, data, reply, flags);
231             } catch (RuntimeException e) {
232                 // The activity manager only throws security exceptions, so let's
233                 // log all others.
234                 if (!(e instanceof SecurityException)) {
235                     Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e);
236                 }
237                 throw e;
238             }
239         }
240 
initForUser(int userHandle)241         public void initForUser(int userHandle) {
242             if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle);
243             String curInteractorStr = Settings.Secure.getStringForUser(
244                     mContext.getContentResolver(),
245                     Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
246             ComponentName curRecognizer = getCurRecognizer(userHandle);
247             VoiceInteractionServiceInfo curInteractorInfo = null;
248             if (DEBUG) Slog.d(TAG, "curInteractorStr=" + curInteractorStr
249                     + " curRecognizer=" + curRecognizer);
250             if (curInteractorStr == null && curRecognizer != null && mEnableService) {
251                 // If there is no interactor setting, that means we are upgrading
252                 // from an older platform version.  If the current recognizer is not
253                 // set or matches the preferred recognizer, then we want to upgrade
254                 // the user to have the default voice interaction service enabled.
255                 // Note that we don't do this for low-RAM devices, since we aren't
256                 // supporting voice interaction services there.
257                 curInteractorInfo = findAvailInteractor(userHandle, curRecognizer.getPackageName());
258                 if (curInteractorInfo != null) {
259                     // Looks good!  We'll apply this one.  To make it happen, we clear the
260                     // recognizer so that we don't think we have anything set and will
261                     // re-apply the settings.
262                     if (DEBUG) Slog.d(TAG, "No set interactor, found avail: "
263                             + curInteractorInfo.getServiceInfo().name);
264                     curRecognizer = null;
265                 }
266             }
267 
268             // If forceInteractorPackage exists, try to apply the interactor from this package if
269             // possible and ignore the regular interactor setting.
270             String forceInteractorPackage =
271                     getForceVoiceInteractionServicePackage(mContext.getResources());
272             if (forceInteractorPackage != null) {
273                 curInteractorInfo = findAvailInteractor(userHandle, forceInteractorPackage);
274                 if (curInteractorInfo != null) {
275                     // We'll apply this one. Clear the recognizer and re-apply the settings.
276                     curRecognizer = null;
277                 }
278             }
279 
280             // If we are on a svelte device, make sure an interactor is not currently
281             // enabled; if it is, turn it off.
282             if (!mEnableService && curInteractorStr != null) {
283                 if (!TextUtils.isEmpty(curInteractorStr)) {
284                     if (DEBUG) Slog.d(TAG, "Svelte device; disabling interactor");
285                     setCurInteractor(null, userHandle);
286                     curInteractorStr = "";
287                 }
288             }
289 
290             if (curRecognizer != null) {
291                 // If we already have at least a recognizer, then we probably want to
292                 // leave things as they are...  unless something has disappeared.
293                 IPackageManager pm = AppGlobals.getPackageManager();
294                 ServiceInfo interactorInfo = null;
295                 ServiceInfo recognizerInfo = null;
296                 ComponentName curInteractor = !TextUtils.isEmpty(curInteractorStr)
297                         ? ComponentName.unflattenFromString(curInteractorStr) : null;
298                 try {
299                     recognizerInfo = pm.getServiceInfo(curRecognizer, 0, userHandle);
300                     if (curInteractor != null) {
301                         interactorInfo = pm.getServiceInfo(curInteractor, 0, userHandle);
302                     }
303                 } catch (RemoteException e) {
304                 }
305                 // If the apps for the currently set components still exist, then all is okay.
306                 if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) {
307                     if (DEBUG) Slog.d(TAG, "Current interactor/recognizer okay, done!");
308                     return;
309                 }
310                 if (DEBUG) Slog.d(TAG, "Bad recognizer (" + recognizerInfo + ") or interactor ("
311                         + interactorInfo + ")");
312             }
313 
314             // Initializing settings, look for an interactor first (but only on non-svelte).
315             if (curInteractorInfo == null && mEnableService) {
316                 curInteractorInfo = findAvailInteractor(userHandle, null);
317             }
318 
319             if (curInteractorInfo != null) {
320                 // Eventually it will be an error to not specify this.
321                 setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName,
322                         curInteractorInfo.getServiceInfo().name), userHandle);
323                 if (curInteractorInfo.getRecognitionService() != null) {
324                     setCurRecognizer(
325                             new ComponentName(curInteractorInfo.getServiceInfo().packageName,
326                                     curInteractorInfo.getRecognitionService()), userHandle);
327                     return;
328                 }
329             }
330 
331             // No voice interactor, we'll just set up a simple recognizer.
332             curRecognizer = findAvailRecognizer(null, userHandle);
333             if (curRecognizer != null) {
334                 if (curInteractorInfo == null) {
335                     setCurInteractor(null, userHandle);
336                 }
337                 setCurRecognizer(curRecognizer, userHandle);
338             }
339         }
340 
shouldEnableService(Resources res)341         private boolean shouldEnableService(Resources res) {
342             // VoiceInteractionService should not be enabled on low ram devices unless it has the config flag.
343             return !ActivityManager.isLowRamDeviceStatic() ||
344                     getForceVoiceInteractionServicePackage(res) != null;
345         }
346 
getForceVoiceInteractionServicePackage(Resources res)347         private String getForceVoiceInteractionServicePackage(Resources res) {
348             String interactorPackage =
349                     res.getString(com.android.internal.R.string.config_forceVoiceInteractionServicePackage);
350             return TextUtils.isEmpty(interactorPackage) ? null : interactorPackage;
351         }
352 
systemRunning(boolean safeMode)353         public void systemRunning(boolean safeMode) {
354             mSafeMode = safeMode;
355 
356             mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(),
357                     UserHandle.ALL, true);
358             new SettingsObserver(UiThread.getHandler());
359 
360             synchronized (this) {
361                 mCurUser = ActivityManager.getCurrentUser();
362                 switchImplementationIfNeededLocked(false);
363             }
364         }
365 
switchUser(int userHandle)366         public void switchUser(int userHandle) {
367             synchronized (this) {
368                 mCurUser = userHandle;
369                 switchImplementationIfNeededLocked(false);
370             }
371         }
372 
switchImplementationIfNeeded(boolean force)373         void switchImplementationIfNeeded(boolean force) {
374             synchronized (this) {
375                 switchImplementationIfNeededLocked(force);
376             }
377         }
378 
switchImplementationIfNeededLocked(boolean force)379         void switchImplementationIfNeededLocked(boolean force) {
380             if (!mSafeMode) {
381                 String curService = Settings.Secure.getStringForUser(
382                         mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
383                 ComponentName serviceComponent = null;
384                 ServiceInfo serviceInfo = null;
385                 if (curService != null && !curService.isEmpty()) {
386                     try {
387                         serviceComponent = ComponentName.unflattenFromString(curService);
388                         serviceInfo = AppGlobals.getPackageManager()
389                                 .getServiceInfo(serviceComponent, 0, mCurUser);
390                     } catch (RuntimeException | RemoteException e) {
391                         Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
392                         serviceComponent = null;
393                         serviceInfo = null;
394                     }
395                 }
396 
397                 if (force || mImpl == null || mImpl.mUser != mCurUser
398                         || !mImpl.mComponent.equals(serviceComponent)) {
399                     unloadAllKeyphraseModels();
400                     if (mImpl != null) {
401                         mImpl.shutdownLocked();
402                     }
403                     if (serviceComponent != null && serviceInfo != null) {
404                         mImpl = new VoiceInteractionManagerServiceImpl(mContext,
405                                 UiThread.getHandler(), this, mCurUser, serviceComponent);
406                         mImpl.startLocked();
407                     } else {
408                         mImpl = null;
409                     }
410                 }
411             }
412         }
413 
findAvailInteractor(int userHandle, String packageName)414         VoiceInteractionServiceInfo findAvailInteractor(int userHandle, String packageName) {
415             List<ResolveInfo> available =
416                     mContext.getPackageManager().queryIntentServicesAsUser(
417                             new Intent(VoiceInteractionService.SERVICE_INTERFACE),
418                             PackageManager.MATCH_DIRECT_BOOT_AWARE
419                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
420                                     | PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userHandle);
421             int numAvailable = available.size();
422 
423             if (numAvailable == 0) {
424                 Slog.w(TAG, "no available voice interaction services found for user " + userHandle);
425                 return null;
426             } else {
427                 // Find first system package.  We never want to allow third party services to
428                 // be automatically selected, because those require approval of the user.
429                 VoiceInteractionServiceInfo foundInfo = null;
430                 for (int i=0; i<numAvailable; i++) {
431                     ServiceInfo cur = available.get(i).serviceInfo;
432                     if ((cur.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
433                         ComponentName comp = new ComponentName(cur.packageName, cur.name);
434                         try {
435                             VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo(
436                                     mContext.getPackageManager(), comp, userHandle);
437                             if (info.getParseError() == null) {
438                                 if (packageName == null || info.getServiceInfo().packageName.equals(
439                                         packageName)) {
440                                     if (foundInfo == null) {
441                                         foundInfo = info;
442                                     } else {
443                                         Slog.w(TAG, "More than one voice interaction service, "
444                                                 + "picking first "
445                                                 + new ComponentName(
446                                                         foundInfo.getServiceInfo().packageName,
447                                                         foundInfo.getServiceInfo().name)
448                                                 + " over "
449                                                 + new ComponentName(cur.packageName, cur.name));
450                                     }
451                                 }
452                             } else {
453                                 Slog.w(TAG, "Bad interaction service " + comp + ": "
454                                         + info.getParseError());
455                             }
456                         } catch (PackageManager.NameNotFoundException e) {
457                             Slog.w(TAG, "Failure looking up interaction service " + comp);
458                         }
459                     }
460                 }
461 
462                 return foundInfo;
463             }
464         }
465 
getCurInteractor(int userHandle)466         ComponentName getCurInteractor(int userHandle) {
467             String curInteractor = Settings.Secure.getStringForUser(
468                     mContext.getContentResolver(),
469                     Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
470             if (TextUtils.isEmpty(curInteractor)) {
471                 return null;
472             }
473             if (DEBUG) Slog.d(TAG, "getCurInteractor curInteractor=" + curInteractor
474                     + " user=" + userHandle);
475             return ComponentName.unflattenFromString(curInteractor);
476         }
477 
setCurInteractor(ComponentName comp, int userHandle)478         void setCurInteractor(ComponentName comp, int userHandle) {
479             Settings.Secure.putStringForUser(mContext.getContentResolver(),
480                     Settings.Secure.VOICE_INTERACTION_SERVICE,
481                     comp != null ? comp.flattenToShortString() : "", userHandle);
482             if (DEBUG) Slog.d(TAG, "setCurInteractor comp=" + comp
483                     + " user=" + userHandle);
484         }
485 
findAvailRecognizer(String prefPackage, int userHandle)486         ComponentName findAvailRecognizer(String prefPackage, int userHandle) {
487             List<ResolveInfo> available =
488                     mContext.getPackageManager().queryIntentServicesAsUser(
489                             new Intent(RecognitionService.SERVICE_INTERFACE), 0, userHandle);
490             int numAvailable = available.size();
491 
492             if (numAvailable == 0) {
493                 Slog.w(TAG, "no available voice recognition services found for user " + userHandle);
494                 return null;
495             } else {
496                 if (prefPackage != null) {
497                     for (int i=0; i<numAvailable; i++) {
498                         ServiceInfo serviceInfo = available.get(i).serviceInfo;
499                         if (prefPackage.equals(serviceInfo.packageName)) {
500                             return new ComponentName(serviceInfo.packageName, serviceInfo.name);
501                         }
502                     }
503                 }
504                 if (numAvailable > 1) {
505                     Slog.w(TAG, "more than one voice recognition service found, picking first");
506                 }
507 
508                 ServiceInfo serviceInfo = available.get(0).serviceInfo;
509                 return new ComponentName(serviceInfo.packageName, serviceInfo.name);
510             }
511         }
512 
getCurRecognizer(int userHandle)513         ComponentName getCurRecognizer(int userHandle) {
514             String curRecognizer = Settings.Secure.getStringForUser(
515                     mContext.getContentResolver(),
516                     Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle);
517             if (TextUtils.isEmpty(curRecognizer)) {
518                 return null;
519             }
520             if (DEBUG) Slog.d(TAG, "getCurRecognizer curRecognizer=" + curRecognizer
521                     + " user=" + userHandle);
522             return ComponentName.unflattenFromString(curRecognizer);
523         }
524 
setCurRecognizer(ComponentName comp, int userHandle)525         void setCurRecognizer(ComponentName comp, int userHandle) {
526             Settings.Secure.putStringForUser(mContext.getContentResolver(),
527                     Settings.Secure.VOICE_RECOGNITION_SERVICE,
528                     comp != null ? comp.flattenToShortString() : "", userHandle);
529             if (DEBUG) Slog.d(TAG, "setCurRecognizer comp=" + comp
530                     + " user=" + userHandle);
531         }
532 
resetCurAssistant(int userHandle)533         void resetCurAssistant(int userHandle) {
534             Settings.Secure.putStringForUser(mContext.getContentResolver(),
535                     Settings.Secure.ASSISTANT, null, userHandle);
536         }
537 
538         @Override
showSession(IVoiceInteractionService service, Bundle args, int flags)539         public void showSession(IVoiceInteractionService service, Bundle args, int flags) {
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                 final long caller = Binder.clearCallingIdentity();
547                 try {
548                     mImpl.showSessionLocked(args, flags, null, null);
549                 } finally {
550                     Binder.restoreCallingIdentity(caller);
551                 }
552             }
553         }
554 
555         @Override
deliverNewSession(IBinder token, IVoiceInteractionSession session, IVoiceInteractor interactor)556         public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
557                 IVoiceInteractor interactor) {
558             synchronized (this) {
559                 if (mImpl == null) {
560                     throw new SecurityException(
561                             "deliverNewSession without running voice interaction service");
562                 }
563                 final long caller = Binder.clearCallingIdentity();
564                 try {
565                     return mImpl.deliverNewSessionLocked(token, session, interactor);
566                 } finally {
567                     Binder.restoreCallingIdentity(caller);
568                 }
569             }
570         }
571 
572         @Override
showSessionFromSession(IBinder token, Bundle sessionArgs, int flags)573         public boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) {
574             synchronized (this) {
575                 if (mImpl == null) {
576                     Slog.w(TAG, "showSessionFromSession without running voice interaction service");
577                     return false;
578                 }
579                 final long caller = Binder.clearCallingIdentity();
580                 try {
581                     return mImpl.showSessionLocked(sessionArgs, flags, null, null);
582                 } finally {
583                     Binder.restoreCallingIdentity(caller);
584                 }
585             }
586         }
587 
588         @Override
hideSessionFromSession(IBinder token)589         public boolean hideSessionFromSession(IBinder token) {
590             synchronized (this) {
591                 if (mImpl == null) {
592                     Slog.w(TAG, "hideSessionFromSession without running voice interaction service");
593                     return false;
594                 }
595                 final long caller = Binder.clearCallingIdentity();
596                 try {
597                     return mImpl.hideSessionLocked();
598                 } finally {
599                     Binder.restoreCallingIdentity(caller);
600                 }
601             }
602         }
603 
604         @Override
startVoiceActivity(IBinder token, Intent intent, String resolvedType)605         public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
606             synchronized (this) {
607                 if (mImpl == null) {
608                     Slog.w(TAG, "startVoiceActivity without running voice interaction service");
609                     return ActivityManager.START_CANCELED;
610                 }
611                 final int callingPid = Binder.getCallingPid();
612                 final int callingUid = Binder.getCallingUid();
613                 final long caller = Binder.clearCallingIdentity();
614                 try {
615                     return mImpl.startVoiceActivityLocked(callingPid, callingUid, token,
616                             intent, resolvedType);
617                 } finally {
618                     Binder.restoreCallingIdentity(caller);
619                 }
620             }
621         }
622 
623         @Override
setKeepAwake(IBinder token, boolean keepAwake)624         public void setKeepAwake(IBinder token, boolean keepAwake) {
625             synchronized (this) {
626                 if (mImpl == null) {
627                     Slog.w(TAG, "setKeepAwake without running voice interaction service");
628                     return;
629                 }
630                 final long caller = Binder.clearCallingIdentity();
631                 try {
632                     mImpl.setKeepAwakeLocked(token, keepAwake);
633                 } finally {
634                     Binder.restoreCallingIdentity(caller);
635                 }
636             }
637         }
638 
639         @Override
closeSystemDialogs(IBinder token)640         public void closeSystemDialogs(IBinder token) {
641             synchronized (this) {
642                 if (mImpl == null) {
643                     Slog.w(TAG, "closeSystemDialogs without running voice interaction service");
644                     return;
645                 }
646                 final long caller = Binder.clearCallingIdentity();
647                 try {
648                     mImpl.closeSystemDialogsLocked(token);
649                 } finally {
650                     Binder.restoreCallingIdentity(caller);
651                 }
652             }
653         }
654 
655         @Override
finish(IBinder token)656         public void finish(IBinder token) {
657             synchronized (this) {
658                 if (mImpl == null) {
659                     Slog.w(TAG, "finish without running voice interaction service");
660                     return;
661                 }
662                 final long caller = Binder.clearCallingIdentity();
663                 try {
664                     mImpl.finishLocked(token, false);
665                 } finally {
666                     Binder.restoreCallingIdentity(caller);
667                 }
668             }
669         }
670 
671         @Override
setDisabledShowContext(int flags)672         public void setDisabledShowContext(int flags) {
673             synchronized (this) {
674                 if (mImpl == null) {
675                     Slog.w(TAG, "setDisabledShowContext without running voice interaction service");
676                     return;
677                 }
678                 final int callingUid = Binder.getCallingUid();
679                 final long caller = Binder.clearCallingIdentity();
680                 try {
681                     mImpl.setDisabledShowContextLocked(callingUid, flags);
682                 } finally {
683                     Binder.restoreCallingIdentity(caller);
684                 }
685             }
686         }
687 
688         @Override
getDisabledShowContext()689         public int getDisabledShowContext() {
690             synchronized (this) {
691                 if (mImpl == null) {
692                     Slog.w(TAG, "getDisabledShowContext without running voice interaction service");
693                     return 0;
694                 }
695                 final int callingUid = Binder.getCallingUid();
696                 final long caller = Binder.clearCallingIdentity();
697                 try {
698                     return mImpl.getDisabledShowContextLocked(callingUid);
699                 } finally {
700                     Binder.restoreCallingIdentity(caller);
701                 }
702             }
703         }
704 
705         @Override
getUserDisabledShowContext()706         public int getUserDisabledShowContext() {
707             synchronized (this) {
708                 if (mImpl == null) {
709                     Slog.w(TAG,
710                             "getUserDisabledShowContext without running voice interaction service");
711                     return 0;
712                 }
713                 final int callingUid = Binder.getCallingUid();
714                 final long caller = Binder.clearCallingIdentity();
715                 try {
716                     return mImpl.getUserDisabledShowContextLocked(callingUid);
717                 } finally {
718                     Binder.restoreCallingIdentity(caller);
719                 }
720             }
721         }
722 
723         //----------------- Model management APIs --------------------------------//
724 
725         @Override
getKeyphraseSoundModel(int keyphraseId, String bcp47Locale)726         public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
727             enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
728 
729             if (bcp47Locale == null) {
730                 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel");
731             }
732 
733             final int callingUid = UserHandle.getCallingUserId();
734             final long caller = Binder.clearCallingIdentity();
735             try {
736                 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
737             } finally {
738                 Binder.restoreCallingIdentity(caller);
739             }
740         }
741 
742         @Override
updateKeyphraseSoundModel(KeyphraseSoundModel model)743         public int updateKeyphraseSoundModel(KeyphraseSoundModel model) {
744             enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
745             if (model == null) {
746                 throw new IllegalArgumentException("Model must not be null");
747             }
748 
749             final long caller = Binder.clearCallingIdentity();
750             try {
751                 if (mDbHelper.updateKeyphraseSoundModel(model)) {
752                     synchronized (this) {
753                         // Notify the voice interaction service of a change in sound models.
754                         if (mImpl != null && mImpl.mService != null) {
755                             mImpl.notifySoundModelsChangedLocked();
756                         }
757                     }
758                     return SoundTriggerInternal.STATUS_OK;
759                 } else {
760                     return SoundTriggerInternal.STATUS_ERROR;
761                 }
762             } finally {
763                 Binder.restoreCallingIdentity(caller);
764             }
765         }
766 
767         @Override
deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale)768         public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
769             enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
770 
771             if (bcp47Locale == null) {
772                 throw new IllegalArgumentException(
773                         "Illegal argument(s) in deleteKeyphraseSoundModel");
774             }
775 
776             final int callingUid = UserHandle.getCallingUserId();
777             final long caller = Binder.clearCallingIdentity();
778             boolean deleted = false;
779             try {
780                 int unloadStatus = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
781                 if (unloadStatus != SoundTriggerInternal.STATUS_OK) {
782                     Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus);
783                 }
784                 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
785                 return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR;
786             } finally {
787                 if (deleted) {
788                     synchronized (this) {
789                         // Notify the voice interaction service of a change in sound models.
790                         if (mImpl != null && mImpl.mService != null) {
791                             mImpl.notifySoundModelsChangedLocked();
792                         }
793                         mLoadedKeyphraseIds.remove(keyphraseId);
794                     }
795                 }
796                 Binder.restoreCallingIdentity(caller);
797             }
798         }
799 
800         //----------------- SoundTrigger APIs --------------------------------//
801         @Override
isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId, String bcp47Locale)802         public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId,
803                 String bcp47Locale) {
804             synchronized (this) {
805                 if (mImpl == null || mImpl.mService == null
806                         || service.asBinder() != mImpl.mService.asBinder()) {
807                     throw new SecurityException(
808                             "Caller is not the current voice interaction service");
809                 }
810             }
811 
812             if (bcp47Locale == null) {
813                 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase");
814             }
815 
816             final int callingUid = UserHandle.getCallingUserId();
817             final long caller = Binder.clearCallingIdentity();
818             try {
819                 KeyphraseSoundModel model =
820                         mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
821                 return model != null;
822             } finally {
823                 Binder.restoreCallingIdentity(caller);
824             }
825         }
826 
827         @Override
getDspModuleProperties(IVoiceInteractionService service)828         public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) {
829             // Allow the call if this is the current voice interaction service.
830             synchronized (this) {
831                 if (mImpl == null || mImpl.mService == null
832                         || service == null || service.asBinder() != mImpl.mService.asBinder()) {
833                     throw new SecurityException(
834                             "Caller is not the current voice interaction service");
835                 }
836 
837                 final long caller = Binder.clearCallingIdentity();
838                 try {
839                     return mSoundTriggerInternal.getModuleProperties();
840                 } finally {
841                     Binder.restoreCallingIdentity(caller);
842                 }
843             }
844         }
845 
846         @Override
startRecognition(IVoiceInteractionService service, int keyphraseId, String bcp47Locale, IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig)847         public int startRecognition(IVoiceInteractionService service, int keyphraseId,
848                 String bcp47Locale, IRecognitionStatusCallback callback,
849                 RecognitionConfig recognitionConfig) {
850             // Allow the call if this is the current voice interaction service.
851             synchronized (this) {
852                 if (mImpl == null || mImpl.mService == null
853                         || service == null || service.asBinder() != mImpl.mService.asBinder()) {
854                     throw new SecurityException(
855                             "Caller is not the current voice interaction service");
856                 }
857 
858                 if (callback == null || recognitionConfig == null || bcp47Locale == null) {
859                     throw new IllegalArgumentException("Illegal argument(s) in startRecognition");
860                 }
861             }
862 
863             int callingUid = UserHandle.getCallingUserId();
864             final long caller = Binder.clearCallingIdentity();
865             try {
866                 KeyphraseSoundModel soundModel =
867                         mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
868                 if (soundModel == null
869                         || soundModel.uuid == null
870                         || soundModel.keyphrases == null) {
871                     Slog.w(TAG, "No matching sound model found in startRecognition");
872                     return SoundTriggerInternal.STATUS_ERROR;
873                 } else {
874                     // Regardless of the status of the start recognition, we need to make sure
875                     // that we unload this model if needed later.
876                     synchronized (this) {
877                         mLoadedKeyphraseIds.add(keyphraseId);
878                     }
879                     return mSoundTriggerInternal.startRecognition(
880                             keyphraseId, soundModel, callback, recognitionConfig);
881                 }
882             } finally {
883                 Binder.restoreCallingIdentity(caller);
884             }
885         }
886 
887         @Override
stopRecognition(IVoiceInteractionService service, int keyphraseId, IRecognitionStatusCallback callback)888         public int stopRecognition(IVoiceInteractionService service, int keyphraseId,
889                 IRecognitionStatusCallback callback) {
890             // Allow the call if this is the current voice interaction service.
891             synchronized (this) {
892                 if (mImpl == null || mImpl.mService == null
893                         || service == null || service.asBinder() != mImpl.mService.asBinder()) {
894                     throw new SecurityException(
895                             "Caller is not the current voice interaction service");
896                 }
897             }
898 
899             final long caller = Binder.clearCallingIdentity();
900             try {
901                 return mSoundTriggerInternal.stopRecognition(keyphraseId, callback);
902             } finally {
903                 Binder.restoreCallingIdentity(caller);
904             }
905         }
906 
unloadAllKeyphraseModels()907         private synchronized void unloadAllKeyphraseModels() {
908             for (int keyphraseId : mLoadedKeyphraseIds) {
909                 final long caller = Binder.clearCallingIdentity();
910                 try {
911                     int status = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
912                     if (status != SoundTriggerInternal.STATUS_OK) {
913                         Slog.w(TAG, "Failed to unload keyphrase " + keyphraseId + ":" + status);
914                     }
915                 } finally {
916                     Binder.restoreCallingIdentity(caller);
917                 }
918             }
919             mLoadedKeyphraseIds.clear();
920         }
921 
922         @Override
getActiveServiceComponentName()923         public ComponentName getActiveServiceComponentName() {
924             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
925             synchronized (this) {
926                 return mImpl != null ? mImpl.mComponent : null;
927             }
928         }
929 
930         @Override
showSessionForActiveService(Bundle args, int sourceFlags, IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken)931         public boolean showSessionForActiveService(Bundle args, int sourceFlags,
932                 IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) {
933             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
934             synchronized (this) {
935                 if (mImpl == null) {
936                     Slog.w(TAG, "showSessionForActiveService without running voice interaction"
937                             + "service");
938                     return false;
939                 }
940                 final long caller = Binder.clearCallingIdentity();
941                 try {
942                     return mImpl.showSessionLocked(args,
943                             sourceFlags
944                                     | VoiceInteractionSession.SHOW_WITH_ASSIST
945                                     | VoiceInteractionSession.SHOW_WITH_SCREENSHOT,
946                             showCallback, activityToken);
947                 } finally {
948                     Binder.restoreCallingIdentity(caller);
949                 }
950             }
951         }
952 
953         @Override
hideCurrentSession()954         public void hideCurrentSession() throws RemoteException {
955             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
956             synchronized (this) {
957                 if (mImpl == null) {
958                     return;
959                 }
960                 final long caller = Binder.clearCallingIdentity();
961                 try {
962                     if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) {
963                         try {
964                             mImpl.mActiveSession.mSession.closeSystemDialogs();
965                         } catch (RemoteException e) {
966                             Log.w(TAG, "Failed to call closeSystemDialogs", e);
967                         }
968                     }
969                 } finally {
970                     Binder.restoreCallingIdentity(caller);
971                 }
972             }
973         }
974 
975         @Override
launchVoiceAssistFromKeyguard()976         public void launchVoiceAssistFromKeyguard() {
977             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
978             synchronized (this) {
979                 if (mImpl == null) {
980                     Slog.w(TAG, "launchVoiceAssistFromKeyguard without running voice interaction"
981                             + "service");
982                     return;
983                 }
984                 final long caller = Binder.clearCallingIdentity();
985                 try {
986                     mImpl.launchVoiceAssistFromKeyguard();
987                 } finally {
988                     Binder.restoreCallingIdentity(caller);
989                 }
990             }
991         }
992 
993         @Override
isSessionRunning()994         public boolean isSessionRunning() {
995             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
996             synchronized (this) {
997                 return mImpl != null && mImpl.mActiveSession != null;
998             }
999         }
1000 
1001         @Override
activeServiceSupportsAssist()1002         public boolean activeServiceSupportsAssist() {
1003             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1004             synchronized (this) {
1005                 return mImpl != null && mImpl.mInfo != null && mImpl.mInfo.getSupportsAssist();
1006             }
1007         }
1008 
1009         @Override
activeServiceSupportsLaunchFromKeyguard()1010         public boolean activeServiceSupportsLaunchFromKeyguard() throws RemoteException {
1011             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1012             synchronized (this) {
1013                 return mImpl != null && mImpl.mInfo != null
1014                         && mImpl.mInfo.getSupportsLaunchFromKeyguard();
1015             }
1016         }
1017 
1018         @Override
onLockscreenShown()1019         public void onLockscreenShown() {
1020             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1021             synchronized (this) {
1022                 if (mImpl == null) {
1023                     return;
1024                 }
1025                 final long caller = Binder.clearCallingIdentity();
1026                 try {
1027                     if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) {
1028                         try {
1029                             mImpl.mActiveSession.mSession.onLockscreenShown();
1030                         } catch (RemoteException e) {
1031                             Log.w(TAG, "Failed to call onLockscreenShown", e);
1032                         }
1033                     }
1034                 } finally {
1035                     Binder.restoreCallingIdentity(caller);
1036                 }
1037             }
1038         }
1039 
1040         @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1041         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1042             if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
1043                     != PackageManager.PERMISSION_GRANTED) {
1044                 pw.println("Permission Denial: can't dump PowerManager from from pid="
1045                         + Binder.getCallingPid()
1046                         + ", uid=" + Binder.getCallingUid());
1047                 return;
1048             }
1049             synchronized (this) {
1050                 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)");
1051                 pw.println("  mEnableService: " + mEnableService);
1052                 if (mImpl == null) {
1053                     pw.println("  (No active implementation)");
1054                     return;
1055                 }
1056                 mImpl.dumpLocked(fd, pw, args);
1057             }
1058             mSoundTriggerInternal.dump(fd, pw, args);
1059         }
1060 
enforceCallingPermission(String permission)1061         private void enforceCallingPermission(String permission) {
1062             if (mContext.checkCallingOrSelfPermission(permission)
1063                     != PackageManager.PERMISSION_GRANTED) {
1064                 throw new SecurityException("Caller does not hold the permission " + permission);
1065             }
1066         }
1067 
1068         class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler)1069             SettingsObserver(Handler handler) {
1070                 super(handler);
1071                 ContentResolver resolver = mContext.getContentResolver();
1072                 resolver.registerContentObserver(Settings.Secure.getUriFor(
1073                         Settings.Secure.VOICE_INTERACTION_SERVICE), false, this,
1074                         UserHandle.USER_ALL);
1075             }
1076 
onChange(boolean selfChange)1077             @Override public void onChange(boolean selfChange) {
1078                 synchronized (VoiceInteractionManagerServiceStub.this) {
1079                     switchImplementationIfNeededLocked(false);
1080                 }
1081             }
1082         }
1083 
1084         PackageMonitor mPackageMonitor = new PackageMonitor() {
1085             @Override
1086             public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
1087                 if (DEBUG) Slog.d(TAG, "onHandleForceStop uid=" + uid + " doit=" + doit);
1088 
1089                 int userHandle = UserHandle.getUserId(uid);
1090                 ComponentName curInteractor = getCurInteractor(userHandle);
1091                 ComponentName curRecognizer = getCurRecognizer(userHandle);
1092                 boolean hit = false;
1093                 for (String pkg : packages) {
1094                     if (curInteractor != null && pkg.equals(curInteractor.getPackageName())) {
1095                         hit = true;
1096                         break;
1097                     } else if (curRecognizer != null
1098                             && pkg.equals(curRecognizer.getPackageName())) {
1099                         hit = true;
1100                         break;
1101                     }
1102                 }
1103                 if (hit && doit) {
1104                     // The user is force stopping our current interactor/recognizer.
1105                     // Clear the current settings and restore default state.
1106                     synchronized (VoiceInteractionManagerServiceStub.this) {
1107                         unloadAllKeyphraseModels();
1108                         if (mImpl != null) {
1109                             mImpl.shutdownLocked();
1110                             mImpl = null;
1111                         }
1112                         setCurInteractor(null, userHandle);
1113                         setCurRecognizer(null, userHandle);
1114                         resetCurAssistant(userHandle);
1115                         initForUser(userHandle);
1116                         switchImplementationIfNeededLocked(true);
1117                     }
1118                 }
1119                 return hit;
1120             }
1121 
1122             @Override
1123             public void onHandleUserStop(Intent intent, int userHandle) {
1124             }
1125 
1126             @Override
1127             public void onSomePackagesChanged() {
1128                 int userHandle = getChangingUserId();
1129                 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle);
1130 
1131                 synchronized (VoiceInteractionManagerServiceStub.this) {
1132                     ComponentName curInteractor = getCurInteractor(userHandle);
1133                     ComponentName curRecognizer = getCurRecognizer(userHandle);
1134                     if (curRecognizer == null) {
1135                         // Could a new recognizer appear when we don't have one pre-installed?
1136                         if (anyPackagesAppearing()) {
1137                             curRecognizer = findAvailRecognizer(null, userHandle);
1138                             if (curRecognizer != null) {
1139                                 setCurRecognizer(curRecognizer, userHandle);
1140                             }
1141                         }
1142                         return;
1143                     }
1144 
1145                     if (curInteractor != null) {
1146                         int change = isPackageDisappearing(curInteractor.getPackageName());
1147                         if (change == PACKAGE_PERMANENT_CHANGE) {
1148                             // The currently set interactor is permanently gone; fall back to
1149                             // the default config.
1150                             setCurInteractor(null, userHandle);
1151                             setCurRecognizer(null, userHandle);
1152                             initForUser(userHandle);
1153                             return;
1154                         }
1155 
1156                         change = isPackageAppearing(curInteractor.getPackageName());
1157                         if (change != PACKAGE_UNCHANGED) {
1158                             // If current interactor is now appearing, for any reason, then
1159                             // restart our connection with it.
1160                             if (mImpl != null && curInteractor.getPackageName().equals(
1161                                     mImpl.mComponent.getPackageName())) {
1162                                 switchImplementationIfNeededLocked(true);
1163                             }
1164                         }
1165                         return;
1166                     }
1167 
1168                     // There is no interactor, so just deal with a simple recognizer.
1169                     int change = isPackageDisappearing(curRecognizer.getPackageName());
1170                     if (change == PACKAGE_PERMANENT_CHANGE
1171                             || change == PACKAGE_TEMPORARY_CHANGE) {
1172                         setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
1173 
1174                     } else if (isPackageModified(curRecognizer.getPackageName())) {
1175                         setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(),
1176                                 userHandle), userHandle);
1177                     }
1178                 }
1179             }
1180         };
1181     }
1182 }
1183