blob: 682f4a412f0edfa2850b5437db6356a3011c85be [file] [log] [blame]
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001/*
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.soundtrigger;
18
19import android.content.Context;
20import android.content.pm.PackageManager;
21import android.Manifest;
22import android.hardware.soundtrigger.IRecognitionStatusCallback;
23import android.hardware.soundtrigger.SoundTrigger;
Arunesh Mishrac722ec412016-01-27 13:29:12 -080024import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -080025import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
Arunesh Mishra55a9b002016-02-01 14:06:37 -080026import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -080027import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
Arunesh Mishraa772e5f2016-01-25 10:33:11 -080028import android.os.Parcel;
29import android.os.ParcelUuid;
30import android.os.RemoteException;
31import android.util.Slog;
32
33import com.android.server.SystemService;
34import com.android.internal.app.ISoundTriggerService;
35
36import java.io.FileDescriptor;
37import java.io.PrintWriter;
38import java.util.UUID;
39
40/**
41 * A single SystemService to manage all sound/voice-based sound models on the DSP.
42 * This services provides apis to manage sound trigger-based sound models via
43 * the ISoundTriggerService interface. This class also publishes a local interface encapsulating
44 * the functionality provided by {@link SoundTriggerHelper} for use by
45 * {@link VoiceInteractionManagerService}.
46 *
47 * @hide
48 */
49public class SoundTriggerService extends SystemService {
50 static final String TAG = "SoundTriggerService";
51 static final boolean DEBUG = false;
52
53 final Context mContext;
54 private final SoundTriggerServiceStub mServiceStub;
55 private final LocalSoundTriggerService mLocalSoundTriggerService;
56 private SoundTriggerDbHelper mDbHelper;
57
58 public SoundTriggerService(Context context) {
59 super(context);
60 mContext = context;
61 mServiceStub = new SoundTriggerServiceStub();
62 mLocalSoundTriggerService = new LocalSoundTriggerService(context);
63 }
64
65 @Override
66 public void onStart() {
67 publishBinderService(Context.SOUND_TRIGGER_SERVICE, mServiceStub);
68 publishLocalService(SoundTriggerInternal.class, mLocalSoundTriggerService);
69 }
70
71 @Override
72 public void onBootPhase(int phase) {
73 if (PHASE_SYSTEM_SERVICES_READY == phase) {
74 mLocalSoundTriggerService.initSoundTriggerHelper();
75 } else if (PHASE_THIRD_PARTY_APPS_CAN_START == phase) {
76 mDbHelper = new SoundTriggerDbHelper(mContext);
77 }
78 }
79
80 @Override
81 public void onStartUser(int userHandle) {
82 }
83
84 @Override
85 public void onSwitchUser(int userHandle) {
86 }
87
88 class SoundTriggerServiceStub extends ISoundTriggerService.Stub {
89 @Override
90 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
91 throws RemoteException {
92 try {
93 return super.onTransact(code, data, reply, flags);
94 } catch (RuntimeException e) {
95 // The activity manager only throws security exceptions, so let's
96 // log all others.
97 if (!(e instanceof SecurityException)) {
98 Slog.wtf(TAG, "SoundTriggerService Crash", e);
99 }
100 throw e;
101 }
102 }
103
104 @Override
105 public void startRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
106 enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
107 if (DEBUG) {
108 Slog.i(TAG, "startRecognition(): Uuid : " + parcelUuid);
109 }
110 }
111
112 @Override
113 public void stopRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
114 enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
115 if (DEBUG) {
116 Slog.i(TAG, "stopRecognition(): Uuid : " + parcelUuid);
117 }
118 }
119
120 @Override
Arunesh Mishrac722ec412016-01-27 13:29:12 -0800121 public SoundTrigger.GenericSoundModel getSoundModel(ParcelUuid soundModelId) {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800122 enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
123 if (DEBUG) {
124 Slog.i(TAG, "getSoundModel(): id = " + soundModelId);
125 }
Arunesh Mishrac722ec412016-01-27 13:29:12 -0800126 SoundTrigger.GenericSoundModel model = mDbHelper.getGenericSoundModel(soundModelId.getUuid());
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800127 if (model == null) {
128 Slog.e(TAG, "Null model in database.");
129 }
130 return model;
131 }
132
133 @Override
Arunesh Mishrac722ec412016-01-27 13:29:12 -0800134 public void updateSoundModel(SoundTrigger.GenericSoundModel soundModel) {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800135 enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
136 if (DEBUG) {
137 Slog.i(TAG, "updateSoundModel(): model = " + soundModel);
138 }
Arunesh Mishrac722ec412016-01-27 13:29:12 -0800139 mDbHelper.updateGenericSoundModel(soundModel);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800140 }
141
142 @Override
143 public void deleteSoundModel(ParcelUuid soundModelId) {
144 enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
145 if (DEBUG) {
146 Slog.i(TAG, "deleteSoundModel(): id = " + soundModelId);
147 }
Arunesh Mishrac722ec412016-01-27 13:29:12 -0800148 mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800149 }
150 }
151
152 public final class LocalSoundTriggerService extends SoundTriggerInternal {
153 private final Context mContext;
154 private SoundTriggerHelper mSoundTriggerHelper;
155
156 LocalSoundTriggerService(Context context) {
157 mContext = context;
158 }
159
160 void initSoundTriggerHelper() {
161 if (mSoundTriggerHelper == null) {
162 mSoundTriggerHelper = new SoundTriggerHelper(mContext);
163 }
164 }
165
166 @Override
167 public int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
168 IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig) {
169 return mSoundTriggerHelper.startRecognition(keyphraseId, soundModel, listener,
170 recognitionConfig);
171 }
172
173 @Override
174 public int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
175 return mSoundTriggerHelper.stopRecognition(keyphraseId, listener);
176 }
177
178 @Override
179 public void stopAllRecognitions() {
180 mSoundTriggerHelper.stopAllRecognitions();
181 }
182
183 @Override
Arunesh Mishra55a9b002016-02-01 14:06:37 -0800184 public ModuleProperties getModuleProperties() {
185 return mSoundTriggerHelper.getModuleProperties();
186 }
187
188 @Override
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800189 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
190 mSoundTriggerHelper.dump(fd, pw, args);
191 }
192 }
193
194 private void enforceCallingPermission(String permission) {
195 if (mContext.checkCallingOrSelfPermission(permission)
196 != PackageManager.PERMISSION_GRANTED) {
197 throw new SecurityException("Caller does not hold the permission " + permission);
198 }
199 }
200}