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