DevicePolicyManagerService.java revision 424991704b5fb7a64f6cf0fcc3f4b1aabbf2a2e0
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.internal.content.PackageMonitor;
20import com.android.internal.os.storage.ExternalStorageFormatter;
21import com.android.internal.util.FastXmlSerializer;
22import com.android.internal.util.JournaledFile;
23import com.android.internal.util.XmlUtils;
24import com.android.internal.widget.LockPatternUtils;
25
26import org.xmlpull.v1.XmlPullParser;
27import org.xmlpull.v1.XmlPullParserException;
28import org.xmlpull.v1.XmlSerializer;
29
30import android.app.Activity;
31import android.app.admin.DeviceAdminInfo;
32import android.app.admin.DeviceAdminReceiver;
33import android.app.admin.DevicePolicyManager;
34import android.app.admin.IDevicePolicyManager;
35import android.content.BroadcastReceiver;
36import android.content.ComponentName;
37import android.content.Context;
38import android.content.Intent;
39import android.content.pm.PackageManager;
40import android.content.pm.ResolveInfo;
41import android.content.pm.PackageManager.NameNotFoundException;
42import android.os.Binder;
43import android.os.IBinder;
44import android.os.IPowerManager;
45import android.os.PowerManager;
46import android.os.RecoverySystem;
47import android.os.RemoteCallback;
48import android.os.RemoteException;
49import android.os.ServiceManager;
50import android.os.SystemClock;
51import android.util.Slog;
52import android.util.PrintWriterPrinter;
53import android.util.Printer;
54import android.util.Xml;
55import android.view.WindowManagerPolicy;
56
57import java.io.File;
58import java.io.FileDescriptor;
59import java.io.FileInputStream;
60import java.io.FileNotFoundException;
61import java.io.FileOutputStream;
62import java.io.IOException;
63import java.io.PrintWriter;
64import java.util.ArrayList;
65import java.util.HashMap;
66import java.util.List;
67
68/**
69 * Implementation of the device policy APIs.
70 */
71public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
72    static final String TAG = "DevicePolicyManagerService";
73
74    final Context mContext;
75    final MyPackageMonitor mMonitor;
76    final PowerManager.WakeLock mWakeLock;
77
78    IPowerManager mIPowerManager;
79
80    int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
81    int mActivePasswordLength = 0;
82    int mFailedPasswordAttempts = 0;
83
84    int mPasswordOwner = -1;
85
86    final HashMap<ComponentName, ActiveAdmin> mAdminMap
87            = new HashMap<ComponentName, ActiveAdmin>();
88    final ArrayList<ActiveAdmin> mAdminList
89            = new ArrayList<ActiveAdmin>();
90
91    static class ActiveAdmin {
92        final DeviceAdminInfo info;
93
94        int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
95        int minimumPasswordLength = 0;
96        long maximumTimeToUnlock = 0;
97        int maximumFailedPasswordsForWipe = 0;
98
99        ActiveAdmin(DeviceAdminInfo _info) {
100            info = _info;
101        }
102
103        int getUid() { return info.getActivityInfo().applicationInfo.uid; }
104
105        void writeToXml(XmlSerializer out)
106                throws IllegalArgumentException, IllegalStateException, IOException {
107            out.startTag(null, "policies");
108            info.writePoliciesToXml(out);
109            out.endTag(null, "policies");
110            if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
111                out.startTag(null, "password-quality");
112                out.attribute(null, "value", Integer.toString(passwordQuality));
113                out.endTag(null, "password-quality");
114                if (minimumPasswordLength > 0) {
115                    out.startTag(null, "min-password-length");
116                    out.attribute(null, "value", Integer.toString(minimumPasswordLength));
117                    out.endTag(null, "mn-password-length");
118                }
119            }
120            if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
121                out.startTag(null, "max-time-to-unlock");
122                out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
123                out.endTag(null, "max-time-to-unlock");
124            }
125            if (maximumFailedPasswordsForWipe != 0) {
126                out.startTag(null, "max-failed-password-wipe");
127                out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
128                out.endTag(null, "max-failed-password-wipe");
129            }
130        }
131
132        void readFromXml(XmlPullParser parser)
133                throws XmlPullParserException, IOException {
134            int outerDepth = parser.getDepth();
135            int type;
136            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
137                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
138                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
139                    continue;
140                }
141                String tag = parser.getName();
142                if ("policies".equals(tag)) {
143                    info.readPoliciesFromXml(parser);
144                } else if ("password-quality".equals(tag)) {
145                    passwordQuality = Integer.parseInt(
146                            parser.getAttributeValue(null, "value"));
147                } else if ("min-password-length".equals(tag)) {
148                    minimumPasswordLength = Integer.parseInt(
149                            parser.getAttributeValue(null, "value"));
150                } else if ("max-time-to-unlock".equals(tag)) {
151                    maximumTimeToUnlock = Long.parseLong(
152                            parser.getAttributeValue(null, "value"));
153                } else if ("max-failed-password-wipe".equals(tag)) {
154                    maximumFailedPasswordsForWipe = Integer.parseInt(
155                            parser.getAttributeValue(null, "value"));
156                } else {
157                    Slog.w(TAG, "Unknown admin tag: " + tag);
158                }
159                XmlUtils.skipCurrentTag(parser);
160            }
161        }
162
163        void dump(String prefix, PrintWriter pw) {
164            pw.print(prefix); pw.print("uid="); pw.println(getUid());
165            pw.print(prefix); pw.println("policies:");
166            ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
167            if (pols != null) {
168                for (int i=0; i<pols.size(); i++) {
169                    pw.print(prefix); pw.print("  "); pw.println(pols.get(i).tag);
170                }
171            }
172            pw.print(prefix); pw.print("passwordQuality=0x");
173                    pw.print(Integer.toHexString(passwordQuality));
174                    pw.print(" minimumPasswordLength=");
175                    pw.println(minimumPasswordLength);
176            pw.print(prefix); pw.print("maximumTimeToUnlock=");
177                    pw.println(maximumTimeToUnlock);
178            pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
179                    pw.println(maximumFailedPasswordsForWipe);
180        }
181    }
182
183    class MyPackageMonitor extends PackageMonitor {
184        public void onSomePackagesChanged() {
185            synchronized (DevicePolicyManagerService.this) {
186                boolean removed = false;
187                for (int i=mAdminList.size()-1; i>=0; i--) {
188                    ActiveAdmin aa = mAdminList.get(i);
189                    int change = isPackageDisappearing(aa.info.getPackageName());
190                    if (change == PACKAGE_PERMANENT_CHANGE
191                            || change == PACKAGE_TEMPORARY_CHANGE) {
192                        Slog.w(TAG, "Admin unexpectedly uninstalled: "
193                                + aa.info.getComponent());
194                        removed = true;
195                        mAdminList.remove(i);
196                    } else if (isPackageModified(aa.info.getPackageName())) {
197                        try {
198                            mContext.getPackageManager().getReceiverInfo(
199                                    aa.info.getComponent(), 0);
200                        } catch (NameNotFoundException e) {
201                            Slog.w(TAG, "Admin package change removed component: "
202                                    + aa.info.getComponent());
203                            removed = true;
204                            mAdminList.remove(i);
205                        }
206                    }
207                }
208                if (removed) {
209                    validatePasswordOwnerLocked();
210                }
211            }
212        }
213    }
214
215    /**
216     * Instantiates the service.
217     */
218    public DevicePolicyManagerService(Context context) {
219        mContext = context;
220        mMonitor = new MyPackageMonitor();
221        mMonitor.register(context, true);
222        mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
223                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
224    }
225
226    private IPowerManager getIPowerManager() {
227        if (mIPowerManager == null) {
228            IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
229            mIPowerManager = IPowerManager.Stub.asInterface(b);
230        }
231        return mIPowerManager;
232    }
233
234    ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
235        ActiveAdmin admin = mAdminMap.get(who);
236        if (admin != null
237                && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
238                && who.getClassName().equals(admin.info.getActivityInfo().name)) {
239            return admin;
240        }
241        return null;
242    }
243
244    ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
245            throws SecurityException {
246        final int callingUid = Binder.getCallingUid();
247        if (who != null) {
248            ActiveAdmin admin = mAdminMap.get(who);
249            if (admin == null) {
250                throw new SecurityException("No active admin " + who);
251            }
252            if (admin.getUid() != callingUid) {
253                throw new SecurityException("Admin " + who + " is not owned by uid "
254                        + Binder.getCallingUid());
255            }
256            if (!admin.info.usesPolicy(reqPolicy)) {
257                throw new SecurityException("Admin " + admin.info.getComponent()
258                        + " did not specify uses-policy for: "
259                        + admin.info.getTagForPolicy(reqPolicy));
260            }
261            return admin;
262        } else {
263            final int N = mAdminList.size();
264            for (int i=0; i<N; i++) {
265                ActiveAdmin admin = mAdminList.get(i);
266                if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
267                    return admin;
268                }
269            }
270            throw new SecurityException("No active admin owned by uid "
271                    + Binder.getCallingUid() + " for policy #" + reqPolicy);
272        }
273    }
274
275    void sendAdminCommandLocked(ActiveAdmin admin, String action) {
276        Intent intent = new Intent(action);
277        intent.setComponent(admin.info.getComponent());
278        mContext.sendBroadcast(intent);
279    }
280
281    void sendAdminCommandLocked(String action, int reqPolicy) {
282        final int N = mAdminList.size();
283        if (N > 0) {
284            for (int i=0; i<N; i++) {
285                ActiveAdmin admin = mAdminList.get(i);
286                if (admin.info.usesPolicy(reqPolicy)) {
287                    sendAdminCommandLocked(admin, action);
288                }
289            }
290        }
291    }
292
293    void removeActiveAdminLocked(ComponentName adminReceiver) {
294        ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
295        if (admin != null) {
296            sendAdminCommandLocked(admin,
297                    DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
298            // XXX need to wait for it to complete.
299            mAdminList.remove(admin);
300            mAdminMap.remove(adminReceiver);
301            validatePasswordOwnerLocked();
302        }
303    }
304
305    public DeviceAdminInfo findAdmin(ComponentName adminName) {
306        Intent resolveIntent = new Intent();
307        resolveIntent.setComponent(adminName);
308        List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
309                resolveIntent, PackageManager.GET_META_DATA);
310        if (infos == null || infos.size() <= 0) {
311            throw new IllegalArgumentException("Unknown admin: " + adminName);
312        }
313
314        try {
315            return new DeviceAdminInfo(mContext, infos.get(0));
316        } catch (XmlPullParserException e) {
317            Slog.w(TAG, "Bad device admin requested: " + adminName, e);
318            return null;
319        } catch (IOException e) {
320            Slog.w(TAG, "Bad device admin requested: " + adminName, e);
321            return null;
322        }
323    }
324
325    private static JournaledFile makeJournaledFile() {
326        final String base = "/data/system/device_policies.xml";
327        return new JournaledFile(new File(base), new File(base + ".tmp"));
328    }
329
330    private void saveSettingsLocked() {
331        JournaledFile journal = makeJournaledFile();
332        FileOutputStream stream = null;
333        try {
334            stream = new FileOutputStream(journal.chooseForWrite(), false);
335            XmlSerializer out = new FastXmlSerializer();
336            out.setOutput(stream, "utf-8");
337            out.startDocument(null, true);
338
339            out.startTag(null, "policies");
340
341            final int N = mAdminList.size();
342            for (int i=0; i<N; i++) {
343                ActiveAdmin ap = mAdminList.get(i);
344                if (ap != null) {
345                    out.startTag(null, "admin");
346                    out.attribute(null, "name", ap.info.getComponent().flattenToString());
347                    ap.writeToXml(out);
348                    out.endTag(null, "admin");
349                }
350            }
351
352            if (mPasswordOwner >= 0) {
353                out.startTag(null, "password-owner");
354                out.attribute(null, "value", Integer.toString(mPasswordOwner));
355                out.endTag(null, "password-owner");
356            }
357
358            if (mFailedPasswordAttempts != 0) {
359                out.startTag(null, "failed-password-attempts");
360                out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
361                out.endTag(null, "failed-password-attempts");
362            }
363
364            if (mActivePasswordQuality != 0 || mActivePasswordLength != 0) {
365                out.startTag(null, "active-password");
366                out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
367                out.attribute(null, "length", Integer.toString(mActivePasswordLength));
368                out.endTag(null, "active-password");
369            }
370
371            out.endTag(null, "policies");
372
373            out.endDocument();
374            stream.close();
375            journal.commit();
376            sendChangedNotification();
377        } catch (IOException e) {
378            try {
379                if (stream != null) {
380                    stream.close();
381                }
382            } catch (IOException ex) {
383                // Ignore
384            }
385            journal.rollback();
386        }
387    }
388
389    private void sendChangedNotification() {
390        Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
391        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
392        mContext.sendBroadcast(intent);
393    }
394
395    private void loadSettingsLocked() {
396        JournaledFile journal = makeJournaledFile();
397        FileInputStream stream = null;
398        File file = journal.chooseForRead();
399        try {
400            stream = new FileInputStream(file);
401            XmlPullParser parser = Xml.newPullParser();
402            parser.setInput(stream, null);
403
404            int type;
405            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
406                    && type != XmlPullParser.START_TAG) {
407            }
408            String tag = parser.getName();
409            if (!"policies".equals(tag)) {
410                throw new XmlPullParserException(
411                        "Settings do not start with policies tag: found " + tag);
412            }
413            type = parser.next();
414            int outerDepth = parser.getDepth();
415            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
416                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
417                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
418                    continue;
419                }
420                tag = parser.getName();
421                if ("admin".equals(tag)) {
422                    String name = parser.getAttributeValue(null, "name");
423                    try {
424                        DeviceAdminInfo dai = findAdmin(
425                                ComponentName.unflattenFromString(name));
426                        if (dai != null) {
427                            ActiveAdmin ap = new ActiveAdmin(dai);
428                            ap.readFromXml(parser);
429                            mAdminMap.put(ap.info.getComponent(), ap);
430                            mAdminList.add(ap);
431                        }
432                    } catch (RuntimeException e) {
433                        Slog.w(TAG, "Failed loading admin " + name, e);
434                    }
435                } else if ("failed-password-attempts".equals(tag)) {
436                    mFailedPasswordAttempts = Integer.parseInt(
437                            parser.getAttributeValue(null, "value"));
438                    XmlUtils.skipCurrentTag(parser);
439                } else if ("password-owner".equals(tag)) {
440                    mPasswordOwner = Integer.parseInt(
441                            parser.getAttributeValue(null, "value"));
442                    XmlUtils.skipCurrentTag(parser);
443                } else if ("active-password".equals(tag)) {
444                    mActivePasswordQuality = Integer.parseInt(
445                            parser.getAttributeValue(null, "quality"));
446                    mActivePasswordLength = Integer.parseInt(
447                            parser.getAttributeValue(null, "length"));
448                    XmlUtils.skipCurrentTag(parser);
449                } else {
450                    Slog.w(TAG, "Unknown tag: " + tag);
451                    XmlUtils.skipCurrentTag(parser);
452                }
453            }
454        } catch (NullPointerException e) {
455            Slog.w(TAG, "failed parsing " + file + " " + e);
456        } catch (NumberFormatException e) {
457            Slog.w(TAG, "failed parsing " + file + " " + e);
458        } catch (XmlPullParserException e) {
459            Slog.w(TAG, "failed parsing " + file + " " + e);
460        } catch (FileNotFoundException e) {
461            // Don't be noisy, this is normal if we haven't defined any policies.
462        } catch (IOException e) {
463            Slog.w(TAG, "failed parsing " + file + " " + e);
464        } catch (IndexOutOfBoundsException e) {
465            Slog.w(TAG, "failed parsing " + file + " " + e);
466        }
467        try {
468            if (stream != null) {
469                stream.close();
470            }
471        } catch (IOException e) {
472            // Ignore
473        }
474
475        // Validate that what we stored for the password quality matches
476        // sufficiently what is currently set.  Note that this is only
477        // a sanity check in case the two get out of sync; this should
478        // never normally happen.
479        LockPatternUtils utils = new LockPatternUtils(mContext);
480        if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
481            Slog.w(TAG, "Active password quality 0x"
482                    + Integer.toHexString(mActivePasswordQuality)
483                    + " does not match actual quality 0x"
484                    + Integer.toHexString(utils.getActivePasswordQuality()));
485            mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
486            mActivePasswordLength = 0;
487        }
488
489        validatePasswordOwnerLocked();
490
491        long timeMs = getMaximumTimeToLock(null);
492        if (timeMs <= 0) {
493            timeMs = Integer.MAX_VALUE;
494        }
495        try {
496            getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
497        } catch (RemoteException e) {
498            Slog.w(TAG, "Failure talking with power manager", e);
499        }
500    }
501
502    static void validateQualityConstant(int quality) {
503        switch (quality) {
504            case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
505            case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
506            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
507            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
508            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
509                return;
510        }
511        throw new IllegalArgumentException("Invalid quality constant: 0x"
512                + Integer.toHexString(quality));
513    }
514
515    void validatePasswordOwnerLocked() {
516        if (mPasswordOwner >= 0) {
517            boolean haveOwner = false;
518            for (int i=mAdminList.size()-1; i>=0; i--) {
519                if (mAdminList.get(i).getUid() == mPasswordOwner) {
520                    haveOwner = true;
521                    break;
522                }
523            }
524            if (!haveOwner) {
525                Slog.w(TAG, "Previous password owner " + mPasswordOwner
526                        + " no longer active; disabling");
527                mPasswordOwner = -1;
528            }
529        }
530    }
531
532    public void systemReady() {
533        synchronized (this) {
534            loadSettingsLocked();
535        }
536    }
537
538    public void setActiveAdmin(ComponentName adminReceiver) {
539        mContext.enforceCallingOrSelfPermission(
540                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
541
542        DeviceAdminInfo info = findAdmin(adminReceiver);
543        if (info == null) {
544            throw new IllegalArgumentException("Bad admin: " + adminReceiver);
545        }
546        synchronized (this) {
547            long ident = Binder.clearCallingIdentity();
548            try {
549                if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
550                    throw new IllegalArgumentException("Admin is already added");
551                }
552                ActiveAdmin admin = new ActiveAdmin(info);
553                mAdminMap.put(adminReceiver, admin);
554                mAdminList.add(admin);
555                saveSettingsLocked();
556                sendAdminCommandLocked(admin,
557                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
558            } finally {
559                Binder.restoreCallingIdentity(ident);
560            }
561        }
562    }
563
564    public boolean isAdminActive(ComponentName adminReceiver) {
565        synchronized (this) {
566            return getActiveAdminUncheckedLocked(adminReceiver) != null;
567        }
568    }
569
570    public List<ComponentName> getActiveAdmins() {
571        synchronized (this) {
572            final int N = mAdminList.size();
573            if (N <= 0) {
574                return null;
575            }
576            ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
577            for (int i=0; i<N; i++) {
578                res.add(mAdminList.get(i).info.getComponent());
579            }
580            return res;
581        }
582    }
583
584    public boolean packageHasActiveAdmins(String packageName) {
585        synchronized (this) {
586            final int N = mAdminList.size();
587            for (int i=0; i<N; i++) {
588                if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
589                    return true;
590                }
591            }
592            return false;
593        }
594    }
595
596    public void removeActiveAdmin(ComponentName adminReceiver) {
597        synchronized (this) {
598            ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
599            if (admin == null) {
600                return;
601            }
602            if (admin.getUid() != Binder.getCallingUid()) {
603                mContext.enforceCallingOrSelfPermission(
604                        android.Manifest.permission.BIND_DEVICE_ADMIN, null);
605            }
606            long ident = Binder.clearCallingIdentity();
607            try {
608                removeActiveAdminLocked(adminReceiver);
609            } finally {
610                Binder.restoreCallingIdentity(ident);
611            }
612        }
613    }
614
615    public void setPasswordQuality(ComponentName who, int quality) {
616        validateQualityConstant(quality);
617
618        synchronized (this) {
619            if (who == null) {
620                throw new NullPointerException("ComponentName is null");
621            }
622            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
623                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
624            if (ap.passwordQuality != quality) {
625                ap.passwordQuality = quality;
626                saveSettingsLocked();
627            }
628        }
629    }
630
631    public int getPasswordQuality(ComponentName who) {
632        synchronized (this) {
633            int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
634
635            if (who != null) {
636                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
637                return admin != null ? admin.passwordQuality : mode;
638            }
639
640            final int N = mAdminList.size();
641            for  (int i=0; i<N; i++) {
642                ActiveAdmin admin = mAdminList.get(i);
643                if (mode < admin.passwordQuality) {
644                    mode = admin.passwordQuality;
645                }
646            }
647            return mode;
648        }
649    }
650
651    public void setPasswordMinimumLength(ComponentName who, int length) {
652        synchronized (this) {
653            if (who == null) {
654                throw new NullPointerException("ComponentName is null");
655            }
656            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
657                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
658            if (ap.minimumPasswordLength != length) {
659                ap.minimumPasswordLength = length;
660                saveSettingsLocked();
661            }
662        }
663    }
664
665    public int getPasswordMinimumLength(ComponentName who) {
666        synchronized (this) {
667            int length = 0;
668
669            if (who != null) {
670                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
671                return admin != null ? admin.minimumPasswordLength : length;
672            }
673
674            final int N = mAdminList.size();
675            for  (int i=0; i<N; i++) {
676                ActiveAdmin admin = mAdminList.get(i);
677                if (length < admin.minimumPasswordLength) {
678                    length = admin.minimumPasswordLength;
679                }
680            }
681            return length;
682        }
683    }
684
685    public boolean isActivePasswordSufficient() {
686        synchronized (this) {
687            // This API can only be called by an active device admin,
688            // so try to retrieve it to check that the caller is one.
689            getActiveAdminForCallerLocked(null,
690                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
691            return mActivePasswordQuality >= getPasswordQuality(null)
692                    && mActivePasswordLength >= getPasswordMinimumLength(null);
693        }
694    }
695
696    public int getCurrentFailedPasswordAttempts() {
697        synchronized (this) {
698            // This API can only be called by an active device admin,
699            // so try to retrieve it to check that the caller is one.
700            getActiveAdminForCallerLocked(null,
701                    DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
702            return mFailedPasswordAttempts;
703        }
704    }
705
706    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
707        synchronized (this) {
708            // This API can only be called by an active device admin,
709            // so try to retrieve it to check that the caller is one.
710            getActiveAdminForCallerLocked(who,
711                    DeviceAdminInfo.USES_POLICY_WIPE_DATA);
712            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
713                    DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
714            if (ap.maximumFailedPasswordsForWipe != num) {
715                ap.maximumFailedPasswordsForWipe = num;
716                saveSettingsLocked();
717            }
718        }
719    }
720
721    public int getMaximumFailedPasswordsForWipe(ComponentName who) {
722        synchronized (this) {
723            int count = 0;
724
725            if (who != null) {
726                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
727                return admin != null ? admin.maximumFailedPasswordsForWipe : count;
728            }
729
730            final int N = mAdminList.size();
731            for  (int i=0; i<N; i++) {
732                ActiveAdmin admin = mAdminList.get(i);
733                if (count == 0) {
734                    count = admin.maximumFailedPasswordsForWipe;
735                } else if (admin.maximumFailedPasswordsForWipe != 0
736                        && count > admin.maximumFailedPasswordsForWipe) {
737                    count = admin.maximumFailedPasswordsForWipe;
738                }
739            }
740            return count;
741        }
742    }
743
744    public boolean resetPassword(String password, int flags) {
745        int quality;
746        synchronized (this) {
747            // This API can only be called by an active device admin,
748            // so try to retrieve it to check that the caller is one.
749            getActiveAdminForCallerLocked(null,
750                    DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
751            quality = getPasswordQuality(null);
752            if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
753                int realQuality = LockPatternUtils.computePasswordQuality(password);
754                if (realQuality < quality) {
755                    Slog.w(TAG, "resetPassword: password quality 0x"
756                            + Integer.toHexString(quality)
757                            + " does not meet required quality 0x"
758                            + Integer.toHexString(quality));
759                    return false;
760                }
761                quality = realQuality;
762            }
763            int length = getPasswordMinimumLength(null);
764            if (password.length() < length) {
765                Slog.w(TAG, "resetPassword: password length " + password.length()
766                        + " does not meet required length " + length);
767                return false;
768            }
769        }
770
771        int callingUid = Binder.getCallingUid();
772        if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
773            Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
774            return false;
775        }
776
777        // Don't do this with the lock held, because it is going to call
778        // back in to the service.
779        long ident = Binder.clearCallingIdentity();
780        try {
781            LockPatternUtils utils = new LockPatternUtils(mContext);
782            utils.saveLockPassword(password, quality);
783            synchronized (this) {
784                int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
785                        != 0 ? callingUid : -1;
786                if (mPasswordOwner != newOwner) {
787                    mPasswordOwner = newOwner;
788                    saveSettingsLocked();
789                }
790            }
791        } finally {
792            Binder.restoreCallingIdentity(ident);
793        }
794
795        return true;
796    }
797
798    public void setMaximumTimeToLock(ComponentName who, long timeMs) {
799        synchronized (this) {
800            if (who == null) {
801                throw new NullPointerException("ComponentName is null");
802            }
803            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
804                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
805            if (ap.maximumTimeToUnlock != timeMs) {
806                ap.maximumTimeToUnlock = timeMs;
807
808                long ident = Binder.clearCallingIdentity();
809                try {
810                    saveSettingsLocked();
811
812                    timeMs = getMaximumTimeToLock(null);
813                    if (timeMs <= 0) {
814                        timeMs = Integer.MAX_VALUE;
815                    }
816
817                    try {
818                        getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
819                    } catch (RemoteException e) {
820                        Slog.w(TAG, "Failure talking with power manager", e);
821                    }
822                } finally {
823                    Binder.restoreCallingIdentity(ident);
824                }
825            }
826        }
827    }
828
829    public long getMaximumTimeToLock(ComponentName who) {
830        synchronized (this) {
831            long time = 0;
832
833            if (who != null) {
834                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
835                return admin != null ? admin.maximumTimeToUnlock : time;
836            }
837
838            final int N = mAdminList.size();
839            for  (int i=0; i<N; i++) {
840                ActiveAdmin admin = mAdminList.get(i);
841                if (time == 0) {
842                    time = admin.maximumTimeToUnlock;
843                } else if (admin.maximumTimeToUnlock != 0
844                        && time > admin.maximumTimeToUnlock) {
845                    time = admin.maximumTimeToUnlock;
846                }
847            }
848            return time;
849        }
850    }
851
852    public void lockNow() {
853        synchronized (this) {
854            // This API can only be called by an active device admin,
855            // so try to retrieve it to check that the caller is one.
856            getActiveAdminForCallerLocked(null,
857                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
858            long ident = Binder.clearCallingIdentity();
859            try {
860                mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
861                        WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
862            } catch (RemoteException e) {
863            } finally {
864                Binder.restoreCallingIdentity(ident);
865            }
866        }
867    }
868
869    void wipeDataLocked(int flags) {
870        if ((flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0) {
871            Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
872            intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
873            mWakeLock.acquire(10000);
874            mContext.startService(intent);
875        } else {
876            try {
877                RecoverySystem.rebootWipeUserData(mContext);
878            } catch (IOException e) {
879                Slog.w(TAG, "Failed requesting data wipe", e);
880            }
881        }
882    }
883
884    public void wipeData(int flags) {
885        synchronized (this) {
886            // This API can only be called by an active device admin,
887            // so try to retrieve it to check that the caller is one.
888            getActiveAdminForCallerLocked(null,
889                    DeviceAdminInfo.USES_POLICY_WIPE_DATA);
890            long ident = Binder.clearCallingIdentity();
891            try {
892                wipeDataLocked(flags);
893            } finally {
894                Binder.restoreCallingIdentity(ident);
895            }
896        }
897    }
898
899    public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
900        mContext.enforceCallingOrSelfPermission(
901                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
902
903        synchronized (this) {
904            ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
905            if (admin == null) {
906                try {
907                    result.sendResult(null);
908                } catch (RemoteException e) {
909                }
910                return;
911            }
912            Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
913            intent.setComponent(admin.info.getComponent());
914            mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
915                @Override
916                public void onReceive(Context context, Intent intent) {
917                    try {
918                        result.sendResult(getResultExtras(false));
919                    } catch (RemoteException e) {
920                    }
921                }
922            }, null, Activity.RESULT_OK, null, null);
923        }
924    }
925
926    public void setActivePasswordState(int quality, int length) {
927        mContext.enforceCallingOrSelfPermission(
928                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
929
930        validateQualityConstant(quality);
931
932        synchronized (this) {
933            if (mActivePasswordQuality != quality || mActivePasswordLength != length
934                    || mFailedPasswordAttempts != 0) {
935                long ident = Binder.clearCallingIdentity();
936                try {
937                    mActivePasswordQuality = quality;
938                    mActivePasswordLength = length;
939                    mFailedPasswordAttempts = 0;
940                    saveSettingsLocked();
941                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
942                            DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
943                } finally {
944                    Binder.restoreCallingIdentity(ident);
945                }
946            }
947        }
948    }
949
950    public void reportFailedPasswordAttempt() {
951        mContext.enforceCallingOrSelfPermission(
952                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
953
954        synchronized (this) {
955            long ident = Binder.clearCallingIdentity();
956            try {
957                mFailedPasswordAttempts++;
958                saveSettingsLocked();
959                int max = getMaximumFailedPasswordsForWipe(null);
960                if (max > 0 && mFailedPasswordAttempts >= max) {
961                    wipeDataLocked(0);
962                }
963                sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
964                        DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
965            } finally {
966                Binder.restoreCallingIdentity(ident);
967            }
968        }
969    }
970
971    public void reportSuccessfulPasswordAttempt() {
972        mContext.enforceCallingOrSelfPermission(
973                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
974
975        synchronized (this) {
976            if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
977                long ident = Binder.clearCallingIdentity();
978                try {
979                    mFailedPasswordAttempts = 0;
980                    mPasswordOwner = -1;
981                    saveSettingsLocked();
982                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
983                            DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
984                } finally {
985                    Binder.restoreCallingIdentity(ident);
986                }
987            }
988        }
989    }
990
991    @Override
992    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
993        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
994                != PackageManager.PERMISSION_GRANTED) {
995
996            pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
997                    + Binder.getCallingPid()
998                    + ", uid=" + Binder.getCallingUid());
999            return;
1000        }
1001
1002        final Printer p = new PrintWriterPrinter(pw);
1003
1004        synchronized (this) {
1005            p.println("Current Device Policy Manager state:");
1006
1007            p.println("  Enabled Device Admins:");
1008            final int N = mAdminList.size();
1009            for (int i=0; i<N; i++) {
1010                ActiveAdmin ap = mAdminList.get(i);
1011                if (ap != null) {
1012                    pw.print("  "); pw.print(ap.info.getComponent().flattenToShortString());
1013                            pw.println(":");
1014                    ap.dump("    ", pw);
1015                }
1016            }
1017
1018            pw.println(" ");
1019            pw.print("  mActivePasswordQuality=0x");
1020                    pw.println(Integer.toHexString(mActivePasswordQuality));
1021            pw.print("  mActivePasswordLength="); pw.println(mActivePasswordLength);
1022            pw.print("  mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1023            pw.print("  mPasswordOwner="); pw.println(mPasswordOwner);
1024        }
1025    }
1026}
1027