blob: e13ddc8174dbb7deb8de98aa25b833c29b3b10e2 [file] [log] [blame]
Dianne Hackbornd6847842010-01-12 18:14:19 -08001/*
2 * Copyright (C) 2010 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;
18
19import com.android.common.FastXmlSerializer;
20
21import org.xmlpull.v1.XmlPullParser;
22import org.xmlpull.v1.XmlPullParserException;
23import org.xmlpull.v1.XmlSerializer;
24
25import android.app.DeviceAdmin;
26import android.app.DeviceAdminInfo;
27import android.app.DevicePolicyManager;
28import android.app.IDevicePolicyManager;
29import android.content.ComponentName;
30import android.content.Context;
31import android.content.Intent;
32import android.content.pm.PackageManager;
33import android.content.pm.ResolveInfo;
34import android.os.Binder;
35import android.util.Log;
36import android.util.Xml;
37
38import java.io.File;
39import java.io.FileInputStream;
40import java.io.FileOutputStream;
41import java.io.IOException;
42import java.util.List;
43
44/**
45 * Implementation of the device policy APIs.
46 */
47public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
48 private static final String TAG = "DevicePolicyManagerService";
49
50 private final Context mContext;
51
52 int mActivePasswordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
53 int mActivePasswordLength = 0;
54 int mFailedPasswordAttempts = 0;
55
56 ActiveAdmin mActiveAdmin;
57
58 static class ActiveAdmin {
59 ActiveAdmin(DeviceAdminInfo _info) {
60 info = _info;
61 }
62
63 final DeviceAdminInfo info;
64 int getUid() { return info.getActivityInfo().applicationInfo.uid; }
65
66 int passwordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
67 int minimumPasswordLength = 0;
68 long maximumTimeToUnlock = 0;
69 }
70
71 /**
72 * Instantiates the service.
73 */
74 public DevicePolicyManagerService(Context context) {
75 mContext = context;
76 }
77
78 ActiveAdmin getActiveAdminForCallerLocked(ComponentName who) throws SecurityException {
79 if (mActiveAdmin != null && mActiveAdmin.getUid() == Binder.getCallingPid()) {
80 if (who != null) {
81 if (!who.getPackageName().equals(mActiveAdmin.info.getActivityInfo().packageName)
82 || !who.getClassName().equals(mActiveAdmin.info.getActivityInfo().name)) {
83 throw new SecurityException("Current admin is not " + who);
84 }
85 }
86 return mActiveAdmin;
87 }
88 throw new SecurityException("Current admin is not owned by uid " + Binder.getCallingUid());
89 }
90
91
92 void sendAdminCommandLocked(ActiveAdmin policy, String action) {
93 Intent intent = new Intent(action);
94 intent.setComponent(policy.info.getComponent());
95 mContext.sendBroadcast(intent);
96 }
97
98 ComponentName getActiveAdminLocked() {
99 if (mActiveAdmin != null) {
100 return mActiveAdmin.info.getComponent();
101 }
102 return null;
103 }
104
105 void removeActiveAdminLocked(ComponentName adminReceiver) {
106 ComponentName cur = getActiveAdminLocked();
107 if (cur != null && cur.equals(adminReceiver)) {
108 sendAdminCommandLocked(mActiveAdmin,
109 DeviceAdmin.ACTION_DEVICE_ADMIN_DISABLED);
110 // XXX need to wait for it to complete.
111 mActiveAdmin = null;
112 }
113 }
114
115 public DeviceAdminInfo findAdmin(ComponentName adminName) {
116 Intent resolveIntent = new Intent();
117 resolveIntent.setComponent(adminName);
118 List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
119 resolveIntent, PackageManager.GET_META_DATA);
120 if (infos == null || infos.size() <= 0) {
121 throw new IllegalArgumentException("Unknown admin: " + adminName);
122 }
123
124 try {
125 return new DeviceAdminInfo(mContext, infos.get(0));
126 } catch (XmlPullParserException e) {
127 Log.w(TAG, "Bad device admin requested: " + adminName, e);
128 return null;
129 } catch (IOException e) {
130 Log.w(TAG, "Bad device admin requested: " + adminName, e);
131 return null;
132 }
133 }
134
135 private static JournaledFile makeJournaledFile() {
136 final String base = "/data/system/device_policies.xml";
137 return new JournaledFile(new File(base), new File(base + ".tmp"));
138 }
139
140 private void saveSettingsLocked() {
141 JournaledFile journal = makeJournaledFile();
142 FileOutputStream stream = null;
143 try {
144 stream = new FileOutputStream(journal.chooseForWrite(), false);
145 XmlSerializer out = new FastXmlSerializer();
146 out.setOutput(stream, "utf-8");
147 out.startDocument(null, true);
148
149 out.startTag(null, "policies");
150
151 ActiveAdmin ap = mActiveAdmin;
152 if (ap != null) {
153 out.startTag(null, "admin");
154 out.attribute(null, "name", ap.info.getComponent().flattenToString());
155 if (ap.passwordMode != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
156 out.startTag(null, "password-mode");
157 out.attribute(null, "value", Integer.toString(ap.passwordMode));
158 out.endTag(null, "password-mode");
159 if (ap.minimumPasswordLength > 0) {
160 out.startTag(null, "min-password-length");
161 out.attribute(null, "value", Integer.toString(ap.minimumPasswordLength));
162 out.endTag(null, "mn-password-length");
163 }
164 }
165 if (ap.maximumTimeToUnlock != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
166 out.startTag(null, "max-time-to-unlock");
167 out.attribute(null, "value", Long.toString(ap.maximumTimeToUnlock));
168 out.endTag(null, "max-time-to-unlock");
169 }
170 out.endTag(null, "admin");
171 }
172 out.endTag(null, "policies");
173
174 out.endDocument();
175 stream.close();
176 journal.commit();
177 } catch (IOException e) {
178 try {
179 if (stream != null) {
180 stream.close();
181 }
182 } catch (IOException ex) {
183 // Ignore
184 }
185 journal.rollback();
186 }
187 }
188
189 private void loadSettingsLocked() {
190 JournaledFile journal = makeJournaledFile();
191 FileInputStream stream = null;
192 File file = journal.chooseForRead();
193 boolean success = false;
194 try {
195 stream = new FileInputStream(file);
196 XmlPullParser parser = Xml.newPullParser();
197 parser.setInput(stream, null);
198
199 int type = parser.next();
200 while (type != XmlPullParser.START_TAG) {
201 type = parser.next();
202 }
203 String tag = parser.getName();
204 if ("policies".equals(tag)) {
205 ActiveAdmin ap = null;
206 do {
207 type = parser.next();
208 if (type == XmlPullParser.START_TAG) {
209 tag = parser.getName();
210 if (ap == null) {
211 if ("admin".equals(tag)) {
212 DeviceAdminInfo dai = findAdmin(
213 ComponentName.unflattenFromString(
214 parser.getAttributeValue(null, "name")));
215 if (dai != null) {
216 ap = new ActiveAdmin(dai);
217 }
218 }
219 } else if ("password-mode".equals(tag)) {
220 ap.passwordMode = Integer.parseInt(
221 parser.getAttributeValue(null, "value"));
222 } else if ("min-password-length".equals(tag)) {
223 ap.minimumPasswordLength = Integer.parseInt(
224 parser.getAttributeValue(null, "value"));
225 } else if ("max-time-to-unlock".equals(tag)) {
226 ap.maximumTimeToUnlock = Long.parseLong(
227 parser.getAttributeValue(null, "value"));
228 }
229 } else if (type == XmlPullParser.END_TAG) {
230 tag = parser.getName();
231 if (ap != null && "admin".equals(tag)) {
232 mActiveAdmin = ap;
233 ap = null;
234 }
235 }
236 } while (type != XmlPullParser.END_DOCUMENT);
237 success = true;
238 }
239 } catch (NullPointerException e) {
240 Log.w(TAG, "failed parsing " + file + " " + e);
241 } catch (NumberFormatException e) {
242 Log.w(TAG, "failed parsing " + file + " " + e);
243 } catch (XmlPullParserException e) {
244 Log.w(TAG, "failed parsing " + file + " " + e);
245 } catch (IOException e) {
246 Log.w(TAG, "failed parsing " + file + " " + e);
247 } catch (IndexOutOfBoundsException e) {
248 Log.w(TAG, "failed parsing " + file + " " + e);
249 }
250 try {
251 if (stream != null) {
252 stream.close();
253 }
254 } catch (IOException e) {
255 // Ignore
256 }
257
258 if (!success) {
259 Log.w(TAG, "No valid start tag found in policies file");
260 }
261 }
262
263 public void systemReady() {
264 synchronized (this) {
265 loadSettingsLocked();
266 }
267 }
268
269 public void setActiveAdmin(ComponentName adminReceiver) {
270 mContext.enforceCallingOrSelfPermission(
271 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
272
273 DeviceAdminInfo info = findAdmin(adminReceiver);
274 if (info == null) {
275 throw new IllegalArgumentException("Bad admin: " + adminReceiver);
276 }
277 synchronized (this) {
278 long ident = Binder.clearCallingIdentity();
279 try {
280 ComponentName cur = getActiveAdminLocked();
281 if (cur != null && cur.equals(adminReceiver)) {
282 throw new IllegalStateException("An admin is already set");
283 }
284 if (cur != null) {
285 removeActiveAdminLocked(adminReceiver);
286 }
287 mActiveAdmin = new ActiveAdmin(info);
288 saveSettingsLocked();
289 sendAdminCommandLocked(mActiveAdmin,
290 DeviceAdmin.ACTION_DEVICE_ADMIN_ENABLED);
291 } finally {
292 Binder.restoreCallingIdentity(ident);
293 }
294 }
295 }
296
297 public ComponentName getActiveAdmin() {
298 synchronized (this) {
299 return getActiveAdminLocked();
300 }
301 }
302
303 public void removeActiveAdmin(ComponentName adminReceiver) {
304 synchronized (this) {
305 if (mActiveAdmin == null || mActiveAdmin.getUid() != Binder.getCallingUid()) {
306 mContext.enforceCallingOrSelfPermission(
307 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
308 }
309 long ident = Binder.clearCallingIdentity();
310 try {
311 removeActiveAdminLocked(adminReceiver);
312 } finally {
313 Binder.restoreCallingIdentity(ident);
314 }
315 }
316 }
317
318 public void setPasswordMode(ComponentName who, int mode) {
319 synchronized (this) {
320 if (who == null) {
321 throw new NullPointerException("ComponentName is null");
322 }
323 ActiveAdmin ap = getActiveAdminForCallerLocked(who);
324 if (ap.passwordMode != mode) {
325 ap.passwordMode = mode;
326 saveSettingsLocked();
327 }
328 }
329 }
330
331 public int getPasswordMode() {
332 synchronized (this) {
333 return mActiveAdmin != null ? mActiveAdmin.passwordMode
334 : DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
335 }
336 }
337
338 public int getActivePasswordMode() {
339 synchronized (this) {
340 // This API can only be called by an active device admin,
341 // so try to retrieve it to check that the caller is one.
342 getActiveAdminForCallerLocked(null);
343 return mActivePasswordMode;
344 }
345 }
346
347 public void setMinimumPasswordLength(ComponentName who, int length) {
348 synchronized (this) {
349 if (who == null) {
350 throw new NullPointerException("ComponentName is null");
351 }
352 ActiveAdmin ap = getActiveAdminForCallerLocked(who);
353 if (ap.minimumPasswordLength != length) {
354 ap.minimumPasswordLength = length;
355 saveSettingsLocked();
356 }
357 }
358 }
359
360 public int getMinimumPasswordLength() {
361 synchronized (this) {
362 return mActiveAdmin != null ? mActiveAdmin.minimumPasswordLength : 0;
363 }
364 }
365
366 public int getActiveMinimumPasswordLength() {
367 synchronized (this) {
368 // This API can only be called by an active device admin,
369 // so try to retrieve it to check that the caller is one.
370 getActiveAdminForCallerLocked(null);
371 return mActivePasswordLength;
372 }
373 }
374
375 public int getCurrentFailedPasswordAttempts() {
376 synchronized (this) {
377 // This API can only be called by an active device admin,
378 // so try to retrieve it to check that the caller is one.
379 getActiveAdminForCallerLocked(null);
380 return mFailedPasswordAttempts;
381 }
382 }
383
384 public void setMaximumTimeToLock(ComponentName who, long timeMs) {
385 synchronized (this) {
386 if (who == null) {
387 throw new NullPointerException("ComponentName is null");
388 }
389 ActiveAdmin ap = getActiveAdminForCallerLocked(who);
390 if (ap.maximumTimeToUnlock != timeMs) {
391 ap.maximumTimeToUnlock = timeMs;
392 saveSettingsLocked();
393 }
394 }
395 }
396
397 public long getMaximumTimeToLock() {
398 synchronized (this) {
399 return mActiveAdmin != null ? mActiveAdmin.maximumTimeToUnlock : 0;
400 }
401 }
402
403 public void wipeData(int flags) {
404 synchronized (this) {
405 // This API can only be called by an active device admin,
406 // so try to retrieve it to check that the caller is one.
407 getActiveAdminForCallerLocked(null);
408 long ident = Binder.clearCallingIdentity();
409 try {
410 Log.w(TAG, "*************** WIPE DATA HERE");
411 } finally {
412 Binder.restoreCallingIdentity(ident);
413 }
414 }
415 }
416
417 public void setActivePasswordState(int mode, int length) {
418 mContext.enforceCallingOrSelfPermission(
419 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
420
421 synchronized (this) {
422 if (mActivePasswordMode != mode || mActivePasswordLength != length
423 || mFailedPasswordAttempts != 0) {
424 long ident = Binder.clearCallingIdentity();
425 try {
426 mActivePasswordMode = mode;
427 mActivePasswordLength = length;
428 mFailedPasswordAttempts = 0;
429 sendAdminCommandLocked(mActiveAdmin,
430 DeviceAdmin.ACTION_PASSWORD_CHANGED);
431 } finally {
432 Binder.restoreCallingIdentity(ident);
433 }
434 }
435 }
436 }
437
438 public void reportFailedPasswordAttempt() {
439 mContext.enforceCallingOrSelfPermission(
440 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
441
442 synchronized (this) {
443 long ident = Binder.clearCallingIdentity();
444 try {
445 mFailedPasswordAttempts++;
446 sendAdminCommandLocked(mActiveAdmin,
447 DeviceAdmin.ACTION_PASSWORD_FAILED);
448 } finally {
449 Binder.restoreCallingIdentity(ident);
450 }
451 }
452 }
453
454 public void reportSuccessfulPasswordAttempt() {
455 mContext.enforceCallingOrSelfPermission(
456 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
457
458 synchronized (this) {
459 if (mFailedPasswordAttempts != 0) {
460 long ident = Binder.clearCallingIdentity();
461 try {
462 mFailedPasswordAttempts = 0;
463 sendAdminCommandLocked(mActiveAdmin,
464 DeviceAdmin.ACTION_PASSWORD_SUCCEEDED);
465 } finally {
466 Binder.restoreCallingIdentity(ident);
467 }
468 }
469 }
470 }
471}