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