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