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