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