DevicePolicyManagerService.java revision 1f35d487ba1a5208e66bc960f35f6e1d874fbd1e
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.AlarmManager;
32import android.app.PendingIntent;
33import android.app.admin.DeviceAdminInfo;
34import android.app.admin.DeviceAdminReceiver;
35import android.app.admin.DevicePolicyManager;
36import android.app.admin.IDevicePolicyManager;
37import android.content.BroadcastReceiver;
38import android.content.ComponentName;
39import android.content.ContentResolver;
40import android.content.Context;
41import android.content.Intent;
42import android.content.IntentFilter;
43import android.content.pm.PackageManager;
44import android.content.pm.PackageManager.NameNotFoundException;
45import android.content.pm.ResolveInfo;
46import android.os.Binder;
47import android.os.Handler;
48import android.os.IBinder;
49import android.os.IPowerManager;
50import android.os.PowerManager;
51import android.os.RecoverySystem;
52import android.os.RemoteCallback;
53import android.os.RemoteException;
54import android.os.ServiceManager;
55import android.os.SystemClock;
56import android.provider.Settings;
57import android.util.PrintWriterPrinter;
58import android.util.Printer;
59import android.util.Slog;
60import android.util.Xml;
61import android.view.WindowManagerPolicy;
62
63import java.io.File;
64import java.io.FileDescriptor;
65import java.io.FileInputStream;
66import java.io.FileNotFoundException;
67import java.io.FileOutputStream;
68import java.io.IOException;
69import java.io.PrintWriter;
70import java.text.DateFormat;
71import java.util.ArrayList;
72import java.util.Date;
73import java.util.HashMap;
74import java.util.List;
75import java.util.Set;
76
77/**
78 * Implementation of the device policy APIs.
79 */
80public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
81    private static final int REQUEST_EXPIRE_PASSWORD = 5571;
82
83    static final String TAG = "DevicePolicyManagerService";
84
85    private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms
86
87    protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
88            = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
89
90    private static final long MS_PER_DAY = 86400 * 1000;
91
92    final Context mContext;
93    final MyPackageMonitor mMonitor;
94    final PowerManager.WakeLock mWakeLock;
95
96    IPowerManager mIPowerManager;
97
98    int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
99    int mActivePasswordLength = 0;
100    int mActivePasswordUpperCase = 0;
101    int mActivePasswordLowerCase = 0;
102    int mActivePasswordLetters = 0;
103    int mActivePasswordNumeric = 0;
104    int mActivePasswordSymbols = 0;
105    int mActivePasswordNonLetter = 0;
106    int mFailedPasswordAttempts = 0;
107
108    int mPasswordOwner = -1;
109    Handler mHandler = new Handler();
110
111    final HashMap<ComponentName, ActiveAdmin> mAdminMap
112            = new HashMap<ComponentName, ActiveAdmin>();
113    final ArrayList<ActiveAdmin> mAdminList
114            = new ArrayList<ActiveAdmin>();
115
116    BroadcastReceiver mReceiver = new BroadcastReceiver() {
117        @Override
118        public void onReceive(Context context, Intent intent) {
119            String action = intent.getAction();
120            if (Intent.ACTION_BOOT_COMPLETED.equals(action)
121                    || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
122                Slog.v(TAG, "Sending password expiration notifications for action " + action);
123                mHandler.post(new Runnable() {
124                    public void run() {
125                        handlePasswordExpirationNotification();
126                    }
127                });
128            }
129        }
130    };
131
132    static class ActiveAdmin {
133        final DeviceAdminInfo info;
134
135        int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
136        int minimumPasswordLength = 0;
137        int passwordHistoryLength = 0;
138        int minimumPasswordUpperCase = 0;
139        int minimumPasswordLowerCase = 0;
140        int minimumPasswordLetters = 1;
141        int minimumPasswordNumeric = 1;
142        int minimumPasswordSymbols = 1;
143        int minimumPasswordNonLetter = 0;
144        long maximumTimeToUnlock = 0;
145        int maximumFailedPasswordsForWipe = 0;
146        long passwordExpirationTimeout = 0L;
147        long passwordExpirationDate = 0L;
148
149        // TODO: review implementation decisions with frameworks team
150        boolean specifiesGlobalProxy = false;
151        String globalProxySpec = null;
152        String globalProxyExclusionList = null;
153
154        ActiveAdmin(DeviceAdminInfo _info) {
155            info = _info;
156        }
157
158        int getUid() { return info.getActivityInfo().applicationInfo.uid; }
159
160        void writeToXml(XmlSerializer out)
161                throws IllegalArgumentException, IllegalStateException, IOException {
162            out.startTag(null, "policies");
163            info.writePoliciesToXml(out);
164            out.endTag(null, "policies");
165            if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
166                out.startTag(null, "password-quality");
167                out.attribute(null, "value", Integer.toString(passwordQuality));
168                out.endTag(null, "password-quality");
169                if (minimumPasswordLength > 0) {
170                    out.startTag(null, "min-password-length");
171                    out.attribute(null, "value", Integer.toString(minimumPasswordLength));
172                    out.endTag(null, "min-password-length");
173                }
174                if(passwordHistoryLength > 0) {
175                    out.startTag(null, "password-history-length");
176                    out.attribute(null, "value", Integer.toString(passwordHistoryLength));
177                    out.endTag(null, "password-history-length");
178                }
179                if (minimumPasswordUpperCase > 0) {
180                    out.startTag(null, "min-password-uppercase");
181                    out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
182                    out.endTag(null, "min-password-uppercase");
183                }
184                if (minimumPasswordLowerCase > 0) {
185                    out.startTag(null, "min-password-lowercase");
186                    out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
187                    out.endTag(null, "min-password-lowercase");
188                }
189                if (minimumPasswordLetters > 0) {
190                    out.startTag(null, "min-password-letters");
191                    out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
192                    out.endTag(null, "min-password-letters");
193                }
194                if (minimumPasswordNumeric > 0) {
195                    out.startTag(null, "min-password-numeric");
196                    out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
197                    out.endTag(null, "min-password-numeric");
198                }
199                if (minimumPasswordSymbols > 0) {
200                    out.startTag(null, "min-password-symbols");
201                    out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
202                    out.endTag(null, "min-password-symbols");
203                }
204                if (minimumPasswordNonLetter > 0) {
205                    out.startTag(null, "min-password-nonletter");
206                    out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
207                    out.endTag(null, "min-password-nonletter");
208                }
209            }
210            if (maximumTimeToUnlock != 0) {
211                out.startTag(null, "max-time-to-unlock");
212                out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
213                out.endTag(null, "max-time-to-unlock");
214            }
215            if (maximumFailedPasswordsForWipe != 0) {
216                out.startTag(null, "max-failed-password-wipe");
217                out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
218                out.endTag(null, "max-failed-password-wipe");
219            }
220            if (specifiesGlobalProxy) {
221                out.startTag(null, "specifies-global-proxy");
222                out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
223                out.endTag(null, "specifies_global_proxy");
224                if (globalProxySpec != null) {
225                    out.startTag(null, "global-proxy-spec");
226                    out.attribute(null, "value", globalProxySpec);
227                    out.endTag(null, "global-proxy-spec");
228                }
229                if (globalProxyExclusionList != null) {
230                    out.startTag(null, "global-proxy-exclusion-list");
231                    out.attribute(null, "value", globalProxyExclusionList);
232                    out.endTag(null, "global-proxy-exclusion-list");
233                }
234            }
235            if (passwordExpirationTimeout != 0L) {
236                out.startTag(null, "password-expiration-timeout");
237                out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
238                out.endTag(null, "password-expiration-timeout");
239            }
240            if (passwordExpirationDate != 0L) {
241                out.startTag(null, "password-expiration-date");
242                out.attribute(null, "value", Long.toString(passwordExpirationDate));
243                out.endTag(null, "password-expiration-date");
244            }
245        }
246
247        void readFromXml(XmlPullParser parser)
248                throws XmlPullParserException, IOException {
249            int outerDepth = parser.getDepth();
250            int type;
251            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
252                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
253                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
254                    continue;
255                }
256                String tag = parser.getName();
257                if ("policies".equals(tag)) {
258                    info.readPoliciesFromXml(parser);
259                } else if ("password-quality".equals(tag)) {
260                    passwordQuality = Integer.parseInt(
261                            parser.getAttributeValue(null, "value"));
262                } else if ("min-password-length".equals(tag)) {
263                    minimumPasswordLength = Integer.parseInt(
264                            parser.getAttributeValue(null, "value"));
265                } else if ("password-history-length".equals(tag)) {
266                    passwordHistoryLength = Integer.parseInt(
267                            parser.getAttributeValue(null, "value"));
268                } else if ("min-password-uppercase".equals(tag)) {
269                    minimumPasswordUpperCase = Integer.parseInt(
270                            parser.getAttributeValue(null, "value"));
271                } else if ("min-password-lowercase".equals(tag)) {
272                    minimumPasswordLowerCase = Integer.parseInt(
273                            parser.getAttributeValue(null, "value"));
274                } else if ("min-password-letters".equals(tag)) {
275                    minimumPasswordLetters = Integer.parseInt(
276                            parser.getAttributeValue(null, "value"));
277                } else if ("min-password-numeric".equals(tag)) {
278                    minimumPasswordNumeric = Integer.parseInt(
279                            parser.getAttributeValue(null, "value"));
280                } else if ("min-password-symbols".equals(tag)) {
281                    minimumPasswordSymbols = Integer.parseInt(
282                            parser.getAttributeValue(null, "value"));
283                } else if ("min-password-nonletter".equals(tag)) {
284                    minimumPasswordNonLetter = Integer.parseInt(
285                            parser.getAttributeValue(null, "value"));
286                } else if ("max-time-to-unlock".equals(tag)) {
287                    maximumTimeToUnlock = Long.parseLong(
288                            parser.getAttributeValue(null, "value"));
289                } else if ("max-failed-password-wipe".equals(tag)) {
290                    maximumFailedPasswordsForWipe = Integer.parseInt(
291                            parser.getAttributeValue(null, "value"));
292                } else if ("specifies-global-proxy".equals(tag)) {
293                    specifiesGlobalProxy = Boolean.getBoolean(
294                            parser.getAttributeValue(null, "value"));
295                } else if ("global-proxy-spec".equals(tag)) {
296                    globalProxySpec =
297                        parser.getAttributeValue(null, "value");
298                } else if ("global-proxy-exclusion-list".equals(tag)) {
299                    globalProxyExclusionList =
300                        parser.getAttributeValue(null, "value");
301                } else if ("password-expiration-timeout".equals(tag)) {
302                    passwordExpirationTimeout = Long.parseLong(
303                            parser.getAttributeValue(null, "value"));
304                } else if ("password-expiration-date".equals(tag)) {
305                    passwordExpirationDate = Long.parseLong(
306                            parser.getAttributeValue(null, "value"));
307                } else {
308                    Slog.w(TAG, "Unknown admin tag: " + tag);
309                }
310                XmlUtils.skipCurrentTag(parser);
311            }
312        }
313
314        void dump(String prefix, PrintWriter pw) {
315            pw.print(prefix); pw.print("uid="); pw.println(getUid());
316            pw.print(prefix); pw.println("policies:");
317            ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
318            if (pols != null) {
319                for (int i=0; i<pols.size(); i++) {
320                    pw.print(prefix); pw.print("  "); pw.println(pols.get(i).tag);
321                }
322            }
323            pw.print(prefix); pw.print("passwordQuality=0x");
324                    pw.println(Integer.toHexString(passwordQuality));
325            pw.print(prefix); pw.print("minimumPasswordLength=");
326                    pw.println(minimumPasswordLength);
327            pw.print(prefix); pw.print("passwordHistoryLength=");
328                    pw.println(passwordHistoryLength);
329            pw.print(prefix); pw.print("minimumPasswordUpperCase=");
330                    pw.println(minimumPasswordUpperCase);
331            pw.print(prefix); pw.print("minimumPasswordLowerCase=");
332                    pw.println(minimumPasswordLowerCase);
333            pw.print(prefix); pw.print("minimumPasswordLetters=");
334                    pw.println(minimumPasswordLetters);
335            pw.print(prefix); pw.print("minimumPasswordNumeric=");
336                    pw.println(minimumPasswordNumeric);
337            pw.print(prefix); pw.print("minimumPasswordSymbols=");
338                    pw.println(minimumPasswordSymbols);
339            pw.print(prefix); pw.print("minimumPasswordNonLetter=");
340                    pw.println(minimumPasswordNonLetter);
341            pw.print(prefix); pw.print("maximumTimeToUnlock=");
342                    pw.println(maximumTimeToUnlock);
343            pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
344                    pw.println(maximumFailedPasswordsForWipe);
345            pw.print(prefix); pw.print("specifiesGlobalProxy=");
346                    pw.println(specifiesGlobalProxy);
347            pw.print(prefix); pw.print("passwordExpirationTimeout=");
348                    pw.println(passwordExpirationTimeout);
349            pw.print(prefix); pw.print("passwordExpirationDate=");
350                    pw.println(passwordExpirationDate);
351            if (globalProxySpec != null) {
352                pw.print(prefix); pw.print("globalProxySpec=");
353                        pw.println(globalProxySpec);
354            }
355            if (globalProxyExclusionList != null) {
356                pw.print(prefix); pw.print("globalProxyEclusionList=");
357                        pw.println(globalProxyExclusionList);
358            }
359        }
360    }
361
362    class MyPackageMonitor extends PackageMonitor {
363        @Override
364        public void onSomePackagesChanged() {
365            synchronized (DevicePolicyManagerService.this) {
366                boolean removed = false;
367                for (int i=mAdminList.size()-1; i>=0; i--) {
368                    ActiveAdmin aa = mAdminList.get(i);
369                    int change = isPackageDisappearing(aa.info.getPackageName());
370                    if (change == PACKAGE_PERMANENT_CHANGE
371                            || change == PACKAGE_TEMPORARY_CHANGE) {
372                        Slog.w(TAG, "Admin unexpectedly uninstalled: "
373                                + aa.info.getComponent());
374                        removed = true;
375                        mAdminList.remove(i);
376                    } else if (isPackageModified(aa.info.getPackageName())) {
377                        try {
378                            mContext.getPackageManager().getReceiverInfo(
379                                    aa.info.getComponent(), 0);
380                        } catch (NameNotFoundException e) {
381                            Slog.w(TAG, "Admin package change removed component: "
382                                    + aa.info.getComponent());
383                            removed = true;
384                            mAdminList.remove(i);
385                        }
386                    }
387                }
388                if (removed) {
389                    validatePasswordOwnerLocked();
390                }
391            }
392        }
393    }
394
395    /**
396     * Instantiates the service.
397     */
398    public DevicePolicyManagerService(Context context) {
399        mContext = context;
400        mMonitor = new MyPackageMonitor();
401        mMonitor.register(context, true);
402        mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
403                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
404        IntentFilter filter = new IntentFilter();
405        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
406        filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
407        context.registerReceiver(mReceiver, filter);
408    }
409
410    protected void setExpirationAlarmCheckLocked(Context context) {
411        final long expiration = getPasswordExpirationLocked(null);
412        final long now = System.currentTimeMillis();
413        final long timeToExpire = expiration - now;
414        final long alarmTime;
415        if (timeToExpire > 0L && timeToExpire < MS_PER_DAY) {
416            // Next expiration is less than a day, set alarm for exact expiration time
417            alarmTime = now + timeToExpire;
418        } else {
419            // Check again in 24 hours...
420            alarmTime = now + MS_PER_DAY;
421        }
422
423        long token = Binder.clearCallingIdentity();
424        try {
425            AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
426            PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD,
427                    new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
428                    PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
429            am.cancel(pi);
430            am.set(AlarmManager.RTC, alarmTime, pi);
431        } finally {
432            Binder.restoreCallingIdentity(token);
433        }
434    }
435
436    private IPowerManager getIPowerManager() {
437        if (mIPowerManager == null) {
438            IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
439            mIPowerManager = IPowerManager.Stub.asInterface(b);
440        }
441        return mIPowerManager;
442    }
443
444    ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
445        ActiveAdmin admin = mAdminMap.get(who);
446        if (admin != null
447                && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
448                && who.getClassName().equals(admin.info.getActivityInfo().name)) {
449            return admin;
450        }
451        return null;
452    }
453
454    ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
455            throws SecurityException {
456        final int callingUid = Binder.getCallingUid();
457        if (who != null) {
458            ActiveAdmin admin = mAdminMap.get(who);
459            if (admin == null) {
460                throw new SecurityException("No active admin " + who);
461            }
462            if (admin.getUid() != callingUid) {
463                throw new SecurityException("Admin " + who + " is not owned by uid "
464                        + Binder.getCallingUid());
465            }
466            if (!admin.info.usesPolicy(reqPolicy)) {
467                throw new SecurityException("Admin " + admin.info.getComponent()
468                        + " did not specify uses-policy for: "
469                        + admin.info.getTagForPolicy(reqPolicy));
470            }
471            return admin;
472        } else {
473            final int N = mAdminList.size();
474            for (int i=0; i<N; i++) {
475                ActiveAdmin admin = mAdminList.get(i);
476                if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
477                    return admin;
478                }
479            }
480            throw new SecurityException("No active admin owned by uid "
481                    + Binder.getCallingUid() + " for policy #" + reqPolicy);
482        }
483    }
484
485    void sendAdminCommandLocked(ActiveAdmin admin, String action) {
486        Intent intent = new Intent(action);
487        intent.setComponent(admin.info.getComponent());
488        if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
489            intent.putExtra("expiration", admin.passwordExpirationDate);
490        }
491        mContext.sendBroadcast(intent);
492    }
493
494    void sendAdminCommandLocked(String action, int reqPolicy) {
495        final int N = mAdminList.size();
496        if (N > 0) {
497            for (int i=0; i<N; i++) {
498                ActiveAdmin admin = mAdminList.get(i);
499                if (admin.info.usesPolicy(reqPolicy)) {
500                    sendAdminCommandLocked(admin, action);
501                }
502            }
503        }
504    }
505
506    void removeActiveAdminLocked(ComponentName adminReceiver) {
507        ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
508        if (admin != null) {
509            boolean doProxyCleanup =
510                admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
511            sendAdminCommandLocked(admin,
512                    DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
513            // XXX need to wait for it to complete.
514            mAdminList.remove(admin);
515            mAdminMap.remove(adminReceiver);
516            validatePasswordOwnerLocked();
517            if (doProxyCleanup) {
518                resetGlobalProxy();
519            }
520        }
521    }
522
523    public DeviceAdminInfo findAdmin(ComponentName adminName) {
524        Intent resolveIntent = new Intent();
525        resolveIntent.setComponent(adminName);
526        List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
527                resolveIntent, PackageManager.GET_META_DATA);
528        if (infos == null || infos.size() <= 0) {
529            throw new IllegalArgumentException("Unknown admin: " + adminName);
530        }
531
532        try {
533            return new DeviceAdminInfo(mContext, infos.get(0));
534        } catch (XmlPullParserException e) {
535            Slog.w(TAG, "Bad device admin requested: " + adminName, e);
536            return null;
537        } catch (IOException e) {
538            Slog.w(TAG, "Bad device admin requested: " + adminName, e);
539            return null;
540        }
541    }
542
543    private static JournaledFile makeJournaledFile() {
544        final String base = "/data/system/device_policies.xml";
545        return new JournaledFile(new File(base), new File(base + ".tmp"));
546    }
547
548    private void saveSettingsLocked() {
549        JournaledFile journal = makeJournaledFile();
550        FileOutputStream stream = null;
551        try {
552            stream = new FileOutputStream(journal.chooseForWrite(), false);
553            XmlSerializer out = new FastXmlSerializer();
554            out.setOutput(stream, "utf-8");
555            out.startDocument(null, true);
556
557            out.startTag(null, "policies");
558
559            final int N = mAdminList.size();
560            for (int i=0; i<N; i++) {
561                ActiveAdmin ap = mAdminList.get(i);
562                if (ap != null) {
563                    out.startTag(null, "admin");
564                    out.attribute(null, "name", ap.info.getComponent().flattenToString());
565                    ap.writeToXml(out);
566                    out.endTag(null, "admin");
567                }
568            }
569
570            if (mPasswordOwner >= 0) {
571                out.startTag(null, "password-owner");
572                out.attribute(null, "value", Integer.toString(mPasswordOwner));
573                out.endTag(null, "password-owner");
574            }
575
576            if (mFailedPasswordAttempts != 0) {
577                out.startTag(null, "failed-password-attempts");
578                out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
579                out.endTag(null, "failed-password-attempts");
580            }
581
582            if (mActivePasswordQuality != 0 || mActivePasswordLength != 0
583                    || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0
584                    || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0
585                    || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) {
586                out.startTag(null, "active-password");
587                out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
588                out.attribute(null, "length", Integer.toString(mActivePasswordLength));
589                out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase));
590                out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase));
591                out.attribute(null, "letters", Integer.toString(mActivePasswordLetters));
592                out.attribute(null, "numeric", Integer
593                        .toString(mActivePasswordNumeric));
594                out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols));
595                out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter));
596                out.endTag(null, "active-password");
597            }
598
599            out.endTag(null, "policies");
600
601            out.endDocument();
602            stream.close();
603            journal.commit();
604            sendChangedNotification();
605        } catch (IOException e) {
606            try {
607                if (stream != null) {
608                    stream.close();
609                }
610            } catch (IOException ex) {
611                // Ignore
612            }
613            journal.rollback();
614        }
615    }
616
617    private void sendChangedNotification() {
618        Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
619        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
620        mContext.sendBroadcast(intent);
621    }
622
623    private void loadSettingsLocked() {
624        JournaledFile journal = makeJournaledFile();
625        FileInputStream stream = null;
626        File file = journal.chooseForRead();
627        try {
628            stream = new FileInputStream(file);
629            XmlPullParser parser = Xml.newPullParser();
630            parser.setInput(stream, null);
631
632            int type;
633            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
634                    && type != XmlPullParser.START_TAG) {
635            }
636            String tag = parser.getName();
637            if (!"policies".equals(tag)) {
638                throw new XmlPullParserException(
639                        "Settings do not start with policies tag: found " + tag);
640            }
641            type = parser.next();
642            int outerDepth = parser.getDepth();
643            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
644                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
645                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
646                    continue;
647                }
648                tag = parser.getName();
649                if ("admin".equals(tag)) {
650                    String name = parser.getAttributeValue(null, "name");
651                    try {
652                        DeviceAdminInfo dai = findAdmin(
653                                ComponentName.unflattenFromString(name));
654                        if (dai != null) {
655                            ActiveAdmin ap = new ActiveAdmin(dai);
656                            ap.readFromXml(parser);
657                            mAdminMap.put(ap.info.getComponent(), ap);
658                            mAdminList.add(ap);
659                        }
660                    } catch (RuntimeException e) {
661                        Slog.w(TAG, "Failed loading admin " + name, e);
662                    }
663                } else if ("failed-password-attempts".equals(tag)) {
664                    mFailedPasswordAttempts = Integer.parseInt(
665                            parser.getAttributeValue(null, "value"));
666                    XmlUtils.skipCurrentTag(parser);
667                } else if ("password-owner".equals(tag)) {
668                    mPasswordOwner = Integer.parseInt(
669                            parser.getAttributeValue(null, "value"));
670                    XmlUtils.skipCurrentTag(parser);
671                } else if ("active-password".equals(tag)) {
672                    mActivePasswordQuality = Integer.parseInt(
673                            parser.getAttributeValue(null, "quality"));
674                    mActivePasswordLength = Integer.parseInt(
675                            parser.getAttributeValue(null, "length"));
676                    mActivePasswordUpperCase = Integer.parseInt(
677                            parser.getAttributeValue(null, "uppercase"));
678                    mActivePasswordLowerCase = Integer.parseInt(
679                            parser.getAttributeValue(null, "lowercase"));
680                    mActivePasswordLetters = Integer.parseInt(
681                            parser.getAttributeValue(null, "letters"));
682                    mActivePasswordNumeric = Integer.parseInt(
683                            parser.getAttributeValue(null, "numeric"));
684                    mActivePasswordSymbols = Integer.parseInt(
685                            parser.getAttributeValue(null, "symbols"));
686                    mActivePasswordNonLetter = Integer.parseInt(
687                            parser.getAttributeValue(null, "nonletter"));
688                    XmlUtils.skipCurrentTag(parser);
689                } else {
690                    Slog.w(TAG, "Unknown tag: " + tag);
691                    XmlUtils.skipCurrentTag(parser);
692                }
693            }
694        } catch (NullPointerException e) {
695            Slog.w(TAG, "failed parsing " + file + " " + e);
696        } catch (NumberFormatException e) {
697            Slog.w(TAG, "failed parsing " + file + " " + e);
698        } catch (XmlPullParserException e) {
699            Slog.w(TAG, "failed parsing " + file + " " + e);
700        } catch (FileNotFoundException e) {
701            // Don't be noisy, this is normal if we haven't defined any policies.
702        } catch (IOException e) {
703            Slog.w(TAG, "failed parsing " + file + " " + e);
704        } catch (IndexOutOfBoundsException e) {
705            Slog.w(TAG, "failed parsing " + file + " " + e);
706        }
707        try {
708            if (stream != null) {
709                stream.close();
710            }
711        } catch (IOException e) {
712            // Ignore
713        }
714
715        // Validate that what we stored for the password quality matches
716        // sufficiently what is currently set.  Note that this is only
717        // a sanity check in case the two get out of sync; this should
718        // never normally happen.
719        LockPatternUtils utils = new LockPatternUtils(mContext);
720        if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
721            Slog.w(TAG, "Active password quality 0x"
722                    + Integer.toHexString(mActivePasswordQuality)
723                    + " does not match actual quality 0x"
724                    + Integer.toHexString(utils.getActivePasswordQuality()));
725            mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
726            mActivePasswordLength = 0;
727            mActivePasswordUpperCase = 0;
728            mActivePasswordLowerCase = 0;
729            mActivePasswordLetters = 0;
730            mActivePasswordNumeric = 0;
731            mActivePasswordSymbols = 0;
732            mActivePasswordNonLetter = 0;
733        }
734
735        validatePasswordOwnerLocked();
736
737        long timeMs = getMaximumTimeToLock(null);
738        if (timeMs <= 0) {
739            timeMs = Integer.MAX_VALUE;
740        }
741        try {
742            getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
743        } catch (RemoteException e) {
744            Slog.w(TAG, "Failure talking with power manager", e);
745        }
746    }
747
748    static void validateQualityConstant(int quality) {
749        switch (quality) {
750            case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
751            case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
752            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
753            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
754            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
755            case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
756                return;
757        }
758        throw new IllegalArgumentException("Invalid quality constant: 0x"
759                + Integer.toHexString(quality));
760    }
761
762    void validatePasswordOwnerLocked() {
763        if (mPasswordOwner >= 0) {
764            boolean haveOwner = false;
765            for (int i=mAdminList.size()-1; i>=0; i--) {
766                if (mAdminList.get(i).getUid() == mPasswordOwner) {
767                    haveOwner = true;
768                    break;
769                }
770            }
771            if (!haveOwner) {
772                Slog.w(TAG, "Previous password owner " + mPasswordOwner
773                        + " no longer active; disabling");
774                mPasswordOwner = -1;
775            }
776        }
777    }
778
779    public void systemReady() {
780        synchronized (this) {
781            loadSettingsLocked();
782        }
783    }
784
785    private void handlePasswordExpirationNotification() {
786        synchronized (this) {
787            final long now = System.currentTimeMillis();
788            final int N = mAdminList.size();
789            if (N <= 0) {
790                return;
791            }
792            for (int i=0; i < N; i++) {
793                ActiveAdmin admin = mAdminList.get(i);
794                if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
795                        && admin.passwordExpirationTimeout > 0L
796                        && admin.passwordExpirationDate > 0L
797                        && now > admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
798                    sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
799                }
800            }
801            setExpirationAlarmCheckLocked(mContext);
802        }
803    }
804
805    public void setActiveAdmin(ComponentName adminReceiver) {
806        mContext.enforceCallingOrSelfPermission(
807                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
808
809        DeviceAdminInfo info = findAdmin(adminReceiver);
810        if (info == null) {
811            throw new IllegalArgumentException("Bad admin: " + adminReceiver);
812        }
813        synchronized (this) {
814            long ident = Binder.clearCallingIdentity();
815            try {
816                if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
817                    throw new IllegalArgumentException("Admin is already added");
818                }
819                ActiveAdmin admin = new ActiveAdmin(info);
820                mAdminMap.put(adminReceiver, admin);
821                mAdminList.add(admin);
822                saveSettingsLocked();
823                sendAdminCommandLocked(admin,
824                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
825            } finally {
826                Binder.restoreCallingIdentity(ident);
827            }
828        }
829    }
830
831    public boolean isAdminActive(ComponentName adminReceiver) {
832        synchronized (this) {
833            return getActiveAdminUncheckedLocked(adminReceiver) != null;
834        }
835    }
836
837    public List<ComponentName> getActiveAdmins() {
838        synchronized (this) {
839            final int N = mAdminList.size();
840            if (N <= 0) {
841                return null;
842            }
843            ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
844            for (int i=0; i<N; i++) {
845                res.add(mAdminList.get(i).info.getComponent());
846            }
847            return res;
848        }
849    }
850
851    public boolean packageHasActiveAdmins(String packageName) {
852        synchronized (this) {
853            final int N = mAdminList.size();
854            for (int i=0; i<N; i++) {
855                if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
856                    return true;
857                }
858            }
859            return false;
860        }
861    }
862
863    public void removeActiveAdmin(ComponentName adminReceiver) {
864        synchronized (this) {
865            ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
866            if (admin == null) {
867                return;
868            }
869            if (admin.getUid() != Binder.getCallingUid()) {
870                mContext.enforceCallingOrSelfPermission(
871                        android.Manifest.permission.BIND_DEVICE_ADMIN, null);
872            }
873            long ident = Binder.clearCallingIdentity();
874            try {
875                removeActiveAdminLocked(adminReceiver);
876            } finally {
877                Binder.restoreCallingIdentity(ident);
878            }
879        }
880    }
881
882    public void setPasswordQuality(ComponentName who, int quality) {
883        validateQualityConstant(quality);
884
885        synchronized (this) {
886            if (who == null) {
887                throw new NullPointerException("ComponentName is null");
888            }
889            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
890                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
891            if (ap.passwordQuality != quality) {
892                ap.passwordQuality = quality;
893                saveSettingsLocked();
894            }
895        }
896    }
897
898    public int getPasswordQuality(ComponentName who) {
899        synchronized (this) {
900            int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
901
902            if (who != null) {
903                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
904                return admin != null ? admin.passwordQuality : mode;
905            }
906
907            final int N = mAdminList.size();
908            for  (int i=0; i<N; i++) {
909                ActiveAdmin admin = mAdminList.get(i);
910                if (mode < admin.passwordQuality) {
911                    mode = admin.passwordQuality;
912                }
913            }
914            return mode;
915        }
916    }
917
918    public void setPasswordMinimumLength(ComponentName who, int length) {
919        synchronized (this) {
920            if (who == null) {
921                throw new NullPointerException("ComponentName is null");
922            }
923            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
924                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
925            if (ap.minimumPasswordLength != length) {
926                ap.minimumPasswordLength = length;
927                saveSettingsLocked();
928            }
929        }
930    }
931
932    public int getPasswordMinimumLength(ComponentName who) {
933        synchronized (this) {
934            int length = 0;
935
936            if (who != null) {
937                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
938                return admin != null ? admin.minimumPasswordLength : length;
939            }
940
941            final int N = mAdminList.size();
942            for  (int i=0; i<N; i++) {
943                ActiveAdmin admin = mAdminList.get(i);
944                if (length < admin.minimumPasswordLength) {
945                    length = admin.minimumPasswordLength;
946                }
947            }
948            return length;
949        }
950    }
951
952    public void setPasswordHistoryLength(ComponentName who, int length) {
953        synchronized (this) {
954            if (who == null) {
955                throw new NullPointerException("ComponentName is null");
956            }
957            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
958                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
959            if (ap.passwordHistoryLength != length) {
960                ap.passwordHistoryLength = length;
961                saveSettingsLocked();
962            }
963        }
964    }
965
966    public int getPasswordHistoryLength(ComponentName who) {
967        synchronized (this) {
968            int length = 0;
969
970            if (who != null) {
971                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
972                return admin != null ? admin.passwordHistoryLength : length;
973            }
974
975            final int N = mAdminList.size();
976            for (int i = 0; i < N; i++) {
977                ActiveAdmin admin = mAdminList.get(i);
978                if (length < admin.passwordHistoryLength) {
979                    length = admin.passwordHistoryLength;
980                }
981            }
982            return length;
983        }
984    }
985
986    public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
987        synchronized (this) {
988            if (who == null) {
989                throw new NullPointerException("ComponentName is null");
990            }
991            if (timeout < 0) {
992                throw new IllegalArgumentException("Timeout must be >= 0 ms");
993            }
994            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
995                    DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
996            // Calling this API automatically bumps the expiration date
997            final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
998            ap.passwordExpirationDate = expiration;
999            ap.passwordExpirationTimeout = timeout;
1000            if (timeout > 0L) {
1001                Slog.w(TAG, "setPasswordExpiration(): password will expire on "
1002                        + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
1003                        .format(new Date(expiration)));
1004            }
1005            saveSettingsLocked();
1006            setExpirationAlarmCheckLocked(mContext); // in case this is the first one
1007        }
1008    }
1009
1010    public long getPasswordExpirationTimeout(ComponentName who) {
1011        synchronized (this) {
1012            long timeout = 0L;
1013            if (who != null) {
1014                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1015                return admin != null ? admin.passwordExpirationTimeout : timeout;
1016            }
1017
1018            final int N = mAdminList.size();
1019            for (int i = 0; i < N; i++) {
1020                ActiveAdmin admin = mAdminList.get(i);
1021                if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
1022                        && timeout > admin.passwordExpirationTimeout)) {
1023                    timeout = admin.passwordExpirationTimeout;
1024                }
1025            }
1026            return timeout;
1027        }
1028    }
1029
1030    private long getPasswordExpirationLocked(ComponentName who) {
1031        long timeout = 0L;
1032        if (who != null) {
1033            ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1034            return admin != null ? admin.passwordExpirationDate : timeout;
1035        }
1036
1037        final int N = mAdminList.size();
1038        for (int i = 0; i < N; i++) {
1039            ActiveAdmin admin = mAdminList.get(i);
1040            if (timeout == 0L || (admin.passwordExpirationDate != 0
1041                    && timeout > admin.passwordExpirationDate)) {
1042                timeout = admin.passwordExpirationDate;
1043            }
1044        }
1045        return timeout;
1046    }
1047
1048    public long getPasswordExpiration(ComponentName who) {
1049        synchronized (this) {
1050            return getPasswordExpirationLocked(who);
1051        }
1052    }
1053
1054    public void setPasswordMinimumUpperCase(ComponentName who, int length) {
1055        synchronized (this) {
1056            if (who == null) {
1057                throw new NullPointerException("ComponentName is null");
1058            }
1059            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1060                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1061            if (ap.minimumPasswordUpperCase != length) {
1062                ap.minimumPasswordUpperCase = length;
1063                saveSettingsLocked();
1064            }
1065        }
1066    }
1067
1068    public int getPasswordMinimumUpperCase(ComponentName who) {
1069        synchronized (this) {
1070            int length = 0;
1071
1072            if (who != null) {
1073                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1074                return admin != null ? admin.minimumPasswordUpperCase : length;
1075            }
1076
1077            final int N = mAdminList.size();
1078            for (int i=0; i<N; i++) {
1079                ActiveAdmin admin = mAdminList.get(i);
1080                if (length < admin.minimumPasswordUpperCase) {
1081                    length = admin.minimumPasswordUpperCase;
1082                }
1083            }
1084            return length;
1085        }
1086    }
1087
1088    public void setPasswordMinimumLowerCase(ComponentName who, int length) {
1089        synchronized (this) {
1090            if (who == null) {
1091                throw new NullPointerException("ComponentName is null");
1092            }
1093            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1094                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1095            if (ap.minimumPasswordLowerCase != length) {
1096                ap.minimumPasswordLowerCase = length;
1097                saveSettingsLocked();
1098            }
1099        }
1100    }
1101
1102    public int getPasswordMinimumLowerCase(ComponentName who) {
1103        synchronized (this) {
1104            int length = 0;
1105
1106            if (who != null) {
1107                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1108                return admin != null ? admin.minimumPasswordLowerCase : length;
1109            }
1110
1111            final int N = mAdminList.size();
1112            for (int i=0; i<N; i++) {
1113                ActiveAdmin admin = mAdminList.get(i);
1114                if (length < admin.minimumPasswordLowerCase) {
1115                    length = admin.minimumPasswordLowerCase;
1116                }
1117            }
1118            return length;
1119        }
1120    }
1121
1122    public void setPasswordMinimumLetters(ComponentName who, int length) {
1123        synchronized (this) {
1124            if (who == null) {
1125                throw new NullPointerException("ComponentName is null");
1126            }
1127            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1128                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1129            if (ap.minimumPasswordLetters != length) {
1130                ap.minimumPasswordLetters = length;
1131                saveSettingsLocked();
1132            }
1133        }
1134    }
1135
1136    public int getPasswordMinimumLetters(ComponentName who) {
1137        synchronized (this) {
1138            int length = 0;
1139
1140            if (who != null) {
1141                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1142                return admin != null ? admin.minimumPasswordLetters : length;
1143            }
1144
1145            final int N = mAdminList.size();
1146            for (int i=0; i<N; i++) {
1147                ActiveAdmin admin = mAdminList.get(i);
1148                if (length < admin.minimumPasswordLetters) {
1149                    length = admin.minimumPasswordLetters;
1150                }
1151            }
1152            return length;
1153        }
1154    }
1155
1156    public void setPasswordMinimumNumeric(ComponentName who, int length) {
1157        synchronized (this) {
1158            if (who == null) {
1159                throw new NullPointerException("ComponentName is null");
1160            }
1161            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1162                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1163            if (ap.minimumPasswordNumeric != length) {
1164                ap.minimumPasswordNumeric = length;
1165                saveSettingsLocked();
1166            }
1167        }
1168    }
1169
1170    public int getPasswordMinimumNumeric(ComponentName who) {
1171        synchronized (this) {
1172            int length = 0;
1173
1174            if (who != null) {
1175                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1176                return admin != null ? admin.minimumPasswordNumeric : length;
1177            }
1178
1179            final int N = mAdminList.size();
1180            for (int i = 0; i < N; i++) {
1181                ActiveAdmin admin = mAdminList.get(i);
1182                if (length < admin.minimumPasswordNumeric) {
1183                    length = admin.minimumPasswordNumeric;
1184                }
1185            }
1186            return length;
1187        }
1188    }
1189
1190    public void setPasswordMinimumSymbols(ComponentName who, int length) {
1191        synchronized (this) {
1192            if (who == null) {
1193                throw new NullPointerException("ComponentName is null");
1194            }
1195            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1196                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1197            if (ap.minimumPasswordSymbols != length) {
1198                ap.minimumPasswordSymbols = length;
1199                saveSettingsLocked();
1200            }
1201        }
1202    }
1203
1204    public int getPasswordMinimumSymbols(ComponentName who) {
1205        synchronized (this) {
1206            int length = 0;
1207
1208            if (who != null) {
1209                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1210                return admin != null ? admin.minimumPasswordSymbols : length;
1211            }
1212
1213            final int N = mAdminList.size();
1214            for  (int i=0; i<N; i++) {
1215                ActiveAdmin admin = mAdminList.get(i);
1216                if (length < admin.minimumPasswordSymbols) {
1217                    length = admin.minimumPasswordSymbols;
1218                }
1219            }
1220            return length;
1221        }
1222    }
1223
1224    public void setPasswordMinimumNonLetter(ComponentName who, int length) {
1225        synchronized (this) {
1226            if (who == null) {
1227                throw new NullPointerException("ComponentName is null");
1228            }
1229            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1230                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1231            if (ap.minimumPasswordNonLetter != length) {
1232                ap.minimumPasswordNonLetter = length;
1233                saveSettingsLocked();
1234            }
1235        }
1236    }
1237
1238    public int getPasswordMinimumNonLetter(ComponentName who) {
1239        synchronized (this) {
1240            int length = 0;
1241
1242            if (who != null) {
1243                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1244                return admin != null ? admin.minimumPasswordNonLetter : length;
1245            }
1246
1247            final int N = mAdminList.size();
1248            for (int i=0; i<N; i++) {
1249                ActiveAdmin admin = mAdminList.get(i);
1250                if (length < admin.minimumPasswordNonLetter) {
1251                    length = admin.minimumPasswordNonLetter;
1252                }
1253            }
1254            return length;
1255        }
1256    }
1257
1258    public boolean isActivePasswordSufficient() {
1259        synchronized (this) {
1260            // This API can only be called by an active device admin,
1261            // so try to retrieve it to check that the caller is one.
1262            getActiveAdminForCallerLocked(null,
1263                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1264            if (mActivePasswordQuality < getPasswordQuality(null)
1265                    || mActivePasswordLength < getPasswordMinimumLength(null)) {
1266                return false;
1267            }
1268            if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1269                return true;
1270            }
1271            return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null)
1272                    && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null)
1273                    && mActivePasswordLetters >= getPasswordMinimumLetters(null)
1274                    && mActivePasswordNumeric >= getPasswordMinimumNumeric(null)
1275                    && mActivePasswordSymbols >= getPasswordMinimumSymbols(null)
1276                    && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null);
1277        }
1278    }
1279
1280    public int getCurrentFailedPasswordAttempts() {
1281        synchronized (this) {
1282            // This API can only be called by an active device admin,
1283            // so try to retrieve it to check that the caller is one.
1284            getActiveAdminForCallerLocked(null,
1285                    DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1286            return mFailedPasswordAttempts;
1287        }
1288    }
1289
1290    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
1291        synchronized (this) {
1292            // This API can only be called by an active device admin,
1293            // so try to retrieve it to check that the caller is one.
1294            getActiveAdminForCallerLocked(who,
1295                    DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1296            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1297                    DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1298            if (ap.maximumFailedPasswordsForWipe != num) {
1299                ap.maximumFailedPasswordsForWipe = num;
1300                saveSettingsLocked();
1301            }
1302        }
1303    }
1304
1305    public int getMaximumFailedPasswordsForWipe(ComponentName who) {
1306        synchronized (this) {
1307            int count = 0;
1308
1309            if (who != null) {
1310                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1311                return admin != null ? admin.maximumFailedPasswordsForWipe : count;
1312            }
1313
1314            final int N = mAdminList.size();
1315            for  (int i=0; i<N; i++) {
1316                ActiveAdmin admin = mAdminList.get(i);
1317                if (count == 0) {
1318                    count = admin.maximumFailedPasswordsForWipe;
1319                } else if (admin.maximumFailedPasswordsForWipe != 0
1320                        && count > admin.maximumFailedPasswordsForWipe) {
1321                    count = admin.maximumFailedPasswordsForWipe;
1322                }
1323            }
1324            return count;
1325        }
1326    }
1327
1328    public boolean resetPassword(String password, int flags) {
1329        int quality;
1330        synchronized (this) {
1331            // This API can only be called by an active device admin,
1332            // so try to retrieve it to check that the caller is one.
1333            getActiveAdminForCallerLocked(null,
1334                    DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
1335            quality = getPasswordQuality(null);
1336            if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
1337                int realQuality = LockPatternUtils.computePasswordQuality(password);
1338                if (realQuality < quality
1339                        && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1340                    Slog.w(TAG, "resetPassword: password quality 0x"
1341                            + Integer.toHexString(quality)
1342                            + " does not meet required quality 0x"
1343                            + Integer.toHexString(quality));
1344                    return false;
1345                }
1346                quality = Math.max(realQuality, quality);
1347            }
1348            int length = getPasswordMinimumLength(null);
1349            if (password.length() < length) {
1350                Slog.w(TAG, "resetPassword: password length " + password.length()
1351                        + " does not meet required length " + length);
1352                return false;
1353            }
1354            if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
1355                int letters = 0;
1356                int uppercase = 0;
1357                int lowercase = 0;
1358                int numbers = 0;
1359                int symbols = 0;
1360                int nonletter = 0;
1361                for (int i = 0; i < password.length(); i++) {
1362                    char c = password.charAt(i);
1363                    if (c >= 'A' && c <= 'Z') {
1364                        letters++;
1365                        uppercase++;
1366                    } else if (c >= 'a' && c <= 'z') {
1367                        letters++;
1368                        lowercase++;
1369                    } else if (c >= '0' && c <= '9') {
1370                        numbers++;
1371                        nonletter++;
1372                    } else {
1373                        symbols++;
1374                        nonletter++;
1375                    }
1376                }
1377                int neededLetters = getPasswordMinimumLetters(null);
1378                if(letters < neededLetters) {
1379                    Slog.w(TAG, "resetPassword: number of letters " + letters
1380                            + " does not meet required number of letters " + neededLetters);
1381                    return false;
1382                }
1383                int neededNumbers = getPasswordMinimumNumeric(null);
1384                if (numbers < neededNumbers) {
1385                    Slog
1386                            .w(TAG, "resetPassword: number of numerical digits " + numbers
1387                                    + " does not meet required number of numerical digits "
1388                                    + neededNumbers);
1389                    return false;
1390                }
1391                int neededLowerCase = getPasswordMinimumLowerCase(null);
1392                if (lowercase < neededLowerCase) {
1393                    Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
1394                            + " does not meet required number of lowercase letters "
1395                            + neededLowerCase);
1396                    return false;
1397                }
1398                int neededUpperCase = getPasswordMinimumUpperCase(null);
1399                if (uppercase < neededUpperCase) {
1400                    Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
1401                            + " does not meet required number of uppercase letters "
1402                            + neededUpperCase);
1403                    return false;
1404                }
1405                int neededSymbols = getPasswordMinimumSymbols(null);
1406                if (symbols < neededSymbols) {
1407                    Slog.w(TAG, "resetPassword: number of special symbols " + symbols
1408                            + " does not meet required number of special symbols " + neededSymbols);
1409                    return false;
1410                }
1411                int neededNonLetter = getPasswordMinimumNonLetter(null);
1412                if (nonletter < neededNonLetter) {
1413                    Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
1414                            + " does not meet required number of non-letter characters "
1415                            + neededNonLetter);
1416                    return false;
1417                }
1418            }
1419
1420            LockPatternUtils utils = new LockPatternUtils(mContext);
1421            if(utils.checkPasswordHistory(password)) {
1422                Slog.w(TAG, "resetPassword: password is the same as one of the last "
1423                        + getPasswordHistoryLength(null) + " passwords");
1424                return false;
1425            }
1426        }
1427
1428        int callingUid = Binder.getCallingUid();
1429        if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
1430            Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
1431            return false;
1432        }
1433
1434        // Don't do this with the lock held, because it is going to call
1435        // back in to the service.
1436        long ident = Binder.clearCallingIdentity();
1437        try {
1438            LockPatternUtils utils = new LockPatternUtils(mContext);
1439            utils.saveLockPassword(password, quality);
1440            synchronized (this) {
1441                int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
1442                        != 0 ? callingUid : -1;
1443                if (mPasswordOwner != newOwner) {
1444                    mPasswordOwner = newOwner;
1445                    saveSettingsLocked();
1446                }
1447            }
1448        } finally {
1449            Binder.restoreCallingIdentity(ident);
1450        }
1451
1452        return true;
1453    }
1454
1455    public void setMaximumTimeToLock(ComponentName who, long timeMs) {
1456        synchronized (this) {
1457            if (who == null) {
1458                throw new NullPointerException("ComponentName is null");
1459            }
1460            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
1461                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
1462            if (ap.maximumTimeToUnlock != timeMs) {
1463                ap.maximumTimeToUnlock = timeMs;
1464
1465                long ident = Binder.clearCallingIdentity();
1466                try {
1467                    saveSettingsLocked();
1468
1469                    timeMs = getMaximumTimeToLock(null);
1470                    if (timeMs <= 0) {
1471                        timeMs = Integer.MAX_VALUE;
1472                    }
1473
1474                    try {
1475                        getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
1476                    } catch (RemoteException e) {
1477                        Slog.w(TAG, "Failure talking with power manager", e);
1478                    }
1479                } finally {
1480                    Binder.restoreCallingIdentity(ident);
1481                }
1482            }
1483        }
1484    }
1485
1486    public long getMaximumTimeToLock(ComponentName who) {
1487        synchronized (this) {
1488            long time = 0;
1489
1490            if (who != null) {
1491                ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
1492                return admin != null ? admin.maximumTimeToUnlock : time;
1493            }
1494
1495            final int N = mAdminList.size();
1496            for  (int i=0; i<N; i++) {
1497                ActiveAdmin admin = mAdminList.get(i);
1498                if (time == 0) {
1499                    time = admin.maximumTimeToUnlock;
1500                } else if (admin.maximumTimeToUnlock != 0
1501                        && time > admin.maximumTimeToUnlock) {
1502                    time = admin.maximumTimeToUnlock;
1503                }
1504            }
1505            return time;
1506        }
1507    }
1508
1509    public void lockNow() {
1510        synchronized (this) {
1511            // This API can only be called by an active device admin,
1512            // so try to retrieve it to check that the caller is one.
1513            getActiveAdminForCallerLocked(null,
1514                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
1515            long ident = Binder.clearCallingIdentity();
1516            try {
1517                mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
1518                        WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
1519            } catch (RemoteException e) {
1520            } finally {
1521                Binder.restoreCallingIdentity(ident);
1522            }
1523        }
1524    }
1525
1526    void wipeDataLocked(int flags) {
1527        if ((flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0) {
1528            Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
1529            intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
1530            mWakeLock.acquire(10000);
1531            mContext.startService(intent);
1532        } else {
1533            try {
1534                RecoverySystem.rebootWipeUserData(mContext);
1535            } catch (IOException e) {
1536                Slog.w(TAG, "Failed requesting data wipe", e);
1537            }
1538        }
1539    }
1540
1541    public void wipeData(int flags) {
1542        synchronized (this) {
1543            // This API can only be called by an active device admin,
1544            // so try to retrieve it to check that the caller is one.
1545            getActiveAdminForCallerLocked(null,
1546                    DeviceAdminInfo.USES_POLICY_WIPE_DATA);
1547            long ident = Binder.clearCallingIdentity();
1548            try {
1549                wipeDataLocked(flags);
1550            } finally {
1551                Binder.restoreCallingIdentity(ident);
1552            }
1553        }
1554    }
1555
1556    public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
1557        mContext.enforceCallingOrSelfPermission(
1558                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1559
1560        synchronized (this) {
1561            ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
1562            if (admin == null) {
1563                try {
1564                    result.sendResult(null);
1565                } catch (RemoteException e) {
1566                }
1567                return;
1568            }
1569            Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
1570            intent.setComponent(admin.info.getComponent());
1571            mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
1572                @Override
1573                public void onReceive(Context context, Intent intent) {
1574                    try {
1575                        result.sendResult(getResultExtras(false));
1576                    } catch (RemoteException e) {
1577                    }
1578                }
1579            }, null, Activity.RESULT_OK, null, null);
1580        }
1581    }
1582
1583    public void setActivePasswordState(int quality, int length, int letters, int uppercase,
1584            int lowercase, int numbers, int symbols, int nonletter) {
1585        mContext.enforceCallingOrSelfPermission(
1586                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1587
1588        validateQualityConstant(quality);
1589
1590        synchronized (this) {
1591            if (mActivePasswordQuality != quality || mActivePasswordLength != length
1592                    || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters
1593                    || mActivePasswordUpperCase != uppercase
1594                    || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers
1595                    || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) {
1596                long ident = Binder.clearCallingIdentity();
1597                try {
1598                    mActivePasswordQuality = quality;
1599                    mActivePasswordLength = length;
1600                    mActivePasswordLetters = letters;
1601                    mActivePasswordLowerCase = lowercase;
1602                    mActivePasswordUpperCase = uppercase;
1603                    mActivePasswordNumeric = numbers;
1604                    mActivePasswordSymbols = symbols;
1605                    mActivePasswordNonLetter = nonletter;
1606                    mFailedPasswordAttempts = 0;
1607                    saveSettingsLocked();
1608                    updatePasswordExpirationsLocked();
1609                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
1610                            DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
1611                } finally {
1612                    Binder.restoreCallingIdentity(ident);
1613                }
1614            }
1615        }
1616    }
1617
1618    private void updatePasswordExpirationsLocked() {
1619        final int N = mAdminList.size();
1620        if (N > 0) {
1621            for (int i=0; i<N; i++) {
1622                ActiveAdmin admin = mAdminList.get(i);
1623                if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
1624                    admin.passwordExpirationDate = System.currentTimeMillis()
1625                            + admin.passwordExpirationTimeout;
1626                }
1627            }
1628            saveSettingsLocked();
1629        }
1630    }
1631
1632    public void reportFailedPasswordAttempt() {
1633        mContext.enforceCallingOrSelfPermission(
1634                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1635
1636        synchronized (this) {
1637            long ident = Binder.clearCallingIdentity();
1638            try {
1639                mFailedPasswordAttempts++;
1640                saveSettingsLocked();
1641                int max = getMaximumFailedPasswordsForWipe(null);
1642                if (max > 0 && mFailedPasswordAttempts >= max) {
1643                    wipeDataLocked(0);
1644                }
1645                sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
1646                        DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1647            } finally {
1648                Binder.restoreCallingIdentity(ident);
1649            }
1650        }
1651    }
1652
1653    public void reportSuccessfulPasswordAttempt() {
1654        mContext.enforceCallingOrSelfPermission(
1655                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
1656
1657        synchronized (this) {
1658            if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
1659                long ident = Binder.clearCallingIdentity();
1660                try {
1661                    mFailedPasswordAttempts = 0;
1662                    mPasswordOwner = -1;
1663                    saveSettingsLocked();
1664                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
1665                            DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
1666                } finally {
1667                    Binder.restoreCallingIdentity(ident);
1668                }
1669            }
1670        }
1671    }
1672
1673    public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
1674            String exclusionList) {
1675        synchronized(this) {
1676            if (who == null) {
1677                throw new NullPointerException("ComponentName is null");
1678            }
1679
1680            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
1681                    DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
1682
1683            // Scan through active admins and find if anyone has already
1684            // set the global proxy.
1685            final int N = mAdminList.size();
1686            Set<ComponentName> compSet = mAdminMap.keySet();
1687            for  (ComponentName component : compSet) {
1688                ActiveAdmin ap = mAdminMap.get(component);
1689                if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
1690                    // Another admin already sets the global proxy
1691                    // Return it to the caller.
1692                    return component;
1693                }
1694            }
1695            if (proxySpec == null) {
1696                admin.specifiesGlobalProxy = false;
1697                admin.globalProxySpec = null;
1698                admin.globalProxyExclusionList = null;
1699            } else {
1700
1701                admin.specifiesGlobalProxy = true;
1702                admin.globalProxySpec = proxySpec;
1703                admin.globalProxyExclusionList = exclusionList;
1704            }
1705
1706            // Reset the global proxy accordingly
1707            // Do this using system permissions, as apps cannot write to secure settings
1708            long origId = Binder.clearCallingIdentity();
1709            resetGlobalProxy();
1710            Binder.restoreCallingIdentity(origId);
1711            return null;
1712        }
1713    }
1714
1715    public ComponentName getGlobalProxyAdmin() {
1716        synchronized(this) {
1717            // Scan through active admins and find if anyone has already
1718            // set the global proxy.
1719            final int N = mAdminList.size();
1720            for (int i = 0; i < N; i++) {
1721                ActiveAdmin ap = mAdminList.get(i);
1722                if (ap.specifiesGlobalProxy) {
1723                    // Device admin sets the global proxy
1724                    // Return it to the caller.
1725                    return ap.info.getComponent();
1726                }
1727            }
1728        }
1729        // No device admin sets the global proxy.
1730        return null;
1731    }
1732
1733    private void resetGlobalProxy() {
1734        final int N = mAdminList.size();
1735        for (int i = 0; i < N; i++) {
1736            ActiveAdmin ap = mAdminList.get(i);
1737            if (ap.specifiesGlobalProxy) {
1738                saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
1739                return;
1740            }
1741        }
1742        // No device admins defining global proxies - reset global proxy settings to none
1743        saveGlobalProxy(null, null);
1744    }
1745
1746    private void saveGlobalProxy(String proxySpec, String exclusionList) {
1747        if (exclusionList == null) {
1748            exclusionList = "";
1749        }
1750        if (proxySpec == null) {
1751            proxySpec = "";
1752        }
1753        // Remove white spaces
1754        proxySpec = proxySpec.trim();
1755        String data[] = proxySpec.split(":");
1756        int proxyPort = 8080;
1757        if (data.length > 1) {
1758            try {
1759                proxyPort = Integer.parseInt(data[1]);
1760            } catch (NumberFormatException e) {}
1761        }
1762        exclusionList = exclusionList.trim();
1763        ContentResolver res = mContext.getContentResolver();
1764        Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, data[0]);
1765        Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, proxyPort);
1766        Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
1767                exclusionList);
1768    }
1769
1770    @Override
1771    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1772        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1773                != PackageManager.PERMISSION_GRANTED) {
1774
1775            pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
1776                    + Binder.getCallingPid()
1777                    + ", uid=" + Binder.getCallingUid());
1778            return;
1779        }
1780
1781        final Printer p = new PrintWriterPrinter(pw);
1782
1783        synchronized (this) {
1784            p.println("Current Device Policy Manager state:");
1785
1786            p.println("  Enabled Device Admins:");
1787            final int N = mAdminList.size();
1788            for (int i=0; i<N; i++) {
1789                ActiveAdmin ap = mAdminList.get(i);
1790                if (ap != null) {
1791                    pw.print("  "); pw.print(ap.info.getComponent().flattenToShortString());
1792                            pw.println(":");
1793                    ap.dump("    ", pw);
1794                }
1795            }
1796
1797            pw.println(" ");
1798            pw.print("  mActivePasswordQuality=0x");
1799                    pw.println(Integer.toHexString(mActivePasswordQuality));
1800            pw.print("  mActivePasswordLength="); pw.println(mActivePasswordLength);
1801            pw.print("  mActivePasswordUpperCase="); pw.println(mActivePasswordUpperCase);
1802            pw.print("  mActivePasswordLowerCase="); pw.println(mActivePasswordLowerCase);
1803            pw.print("  mActivePasswordLetters="); pw.println(mActivePasswordLetters);
1804            pw.print("  mActivePasswordNumeric="); pw.println(mActivePasswordNumeric);
1805            pw.print("  mActivePasswordSymbols="); pw.println(mActivePasswordSymbols);
1806            pw.print("  mActivePasswordNonLetter="); pw.println(mActivePasswordNonLetter);
1807            pw.print("  mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
1808            pw.print("  mPasswordOwner="); pw.println(mPasswordOwner);
1809        }
1810    }
1811}
1812