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