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