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