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