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