152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani/*
252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * Copyright (C) 2012 The Android Open Source Project
352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani *
452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * Licensed under the Apache License, Version 2.0 (the "License");
552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * you may not use this file except in compliance with the License.
652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * You may obtain a copy of the License at
752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani *
852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani *      http://www.apache.org/licenses/LICENSE-2.0
952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani *
1052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * Unless required by applicable law or agreed to in writing, software
1152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * distributed under the License is distributed on an "AS IS" BASIS,
1252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * See the License for the specific language governing permissions and
1452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * limitations under the License.
1552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani */
1652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
1752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasanipackage com.android.internal.widget;
1852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
1952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.content.ContentResolver;
2052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.content.ContentValues;
2152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.content.Context;
2252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.database.Cursor;
2352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.database.sqlite.SQLiteDatabase;
2452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.database.sqlite.SQLiteOpenHelper;
2552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.os.Binder;
2661f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasaniimport android.os.Environment;
2752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.os.RemoteException;
28d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasaniimport android.os.SystemProperties;
29f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle;
3052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.provider.Settings;
3152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.provider.Settings.Secure;
3252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.text.TextUtils;
3352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport android.util.Slog;
3452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
3552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport java.io.File;
3652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport java.io.FileNotFoundException;
3752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport java.io.IOException;
3852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport java.io.RandomAccessFile;
3952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasaniimport java.util.Arrays;
4052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
4152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani/**
4252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * Keeps the lock pattern/password data and related settings for each user.
4352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * Used by LockPatternUtils. Needs to be a service because Settings app also needs
4452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * to be able to save lockscreen information for secondary users.
4552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani * @hide
4652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani */
4752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasanipublic class LockSettingsService extends ILockSettings.Stub {
4852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
4952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private final DatabaseHelper mOpenHelper;
5052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String TAG = "LockSettingsService";
5152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
5252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String TABLE = "locksettings";
5352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String COLUMN_KEY = "name";
5452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String COLUMN_USERID = "user";
5552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String COLUMN_VALUE = "value";
5652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
5752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String[] COLUMNS_FOR_QUERY = {
5852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        COLUMN_VALUE
5952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    };
6052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
6152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String SYSTEM_DIRECTORY = "/system/";
6252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String LOCK_PATTERN_FILE = "gesture.key";
6352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String LOCK_PASSWORD_FILE = "password.key";
6452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
6552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private final Context mContext;
6652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
6752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public LockSettingsService(Context context) {
6852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        mContext = context;
6952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        // Open the database
7052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        mOpenHelper = new DatabaseHelper(mContext);
7152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
7252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
7352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void systemReady() {
7452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        migrateOldData();
7552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
7652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
7752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private void migrateOldData() {
7852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
7952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (getString("migrated", null, 0) != null) {
8052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                // Already migrated
8152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                return;
8252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
8352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
8452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            final ContentResolver cr = mContext.getContentResolver();
8552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            for (String validSetting : VALID_SETTINGS) {
8652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                String value = Settings.Secure.getString(cr, validSetting);
8752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                if (value != null) {
8852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    setString(validSetting, value, 0);
8952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                }
9052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
9152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // No need to move the password / pattern files. They're already in the right place.
9252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            setString("migrated", "true", 0);
9352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.i(TAG, "Migrated lock settings to new location");
9452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (RemoteException re) {
9552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.e(TAG, "Unable to migrate old data");
9652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
9752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
9852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
9952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final void checkWritePermission(int userId) {
10052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        final int callingUid = Binder.getCallingUid();
101f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        if (UserHandle.getAppId(callingUid) != android.os.Process.SYSTEM_UID) {
10252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            throw new SecurityException("uid=" + callingUid
10352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    + " not authorized to write lock settings");
10452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
10552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
10652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
10752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final void checkPasswordReadPermission(int userId) {
10852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        final int callingUid = Binder.getCallingUid();
109f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        if (UserHandle.getAppId(callingUid) != android.os.Process.SYSTEM_UID) {
11052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            throw new SecurityException("uid=" + callingUid
11152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    + " not authorized to read lock password");
11252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
11352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
11452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
11552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final void checkReadPermission(int userId) {
11652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        final int callingUid = Binder.getCallingUid();
117f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        if (UserHandle.getAppId(callingUid) != android.os.Process.SYSTEM_UID
118f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn                && UserHandle.getUserId(callingUid) != userId) {
11952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            throw new SecurityException("uid=" + callingUid
12052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    + " not authorized to read settings of user " + userId);
12152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
12252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
12352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
12452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
12552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void setBoolean(String key, boolean value, int userId) throws RemoteException {
12652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkWritePermission(userId);
12752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
12852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        writeToDb(key, value ? "1" : "0", userId);
12952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
13052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
13152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
13252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void setLong(String key, long value, int userId) throws RemoteException {
13352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkWritePermission(userId);
13452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
13552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        writeToDb(key, Long.toString(value), userId);
13652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
13752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
13852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
13952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void setString(String key, String value, int userId) throws RemoteException {
14052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkWritePermission(userId);
14152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
14252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        writeToDb(key, value, userId);
14352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
14452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
14552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
14652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
14752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        //checkReadPermission(userId);
14852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
14952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        String value = readFromDb(key, null, userId);
15052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return TextUtils.isEmpty(value) ?
15152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                defaultValue : (value.equals("1") || value.equals("true"));
15252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
15352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
15452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
15552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public long getLong(String key, long defaultValue, int userId) throws RemoteException {
15652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        //checkReadPermission(userId);
15752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
15852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        String value = readFromDb(key, null, userId);
15952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
16052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
16152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
16252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
16352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public String getString(String key, String defaultValue, int userId) throws RemoteException {
16452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        //checkReadPermission(userId);
16552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
16652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return readFromDb(key, defaultValue, userId);
16752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
16852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
16952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private String getLockPatternFilename(int userId) {
17052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        String dataSystemDirectory =
17152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                android.os.Environment.getDataDirectory().getAbsolutePath() +
17252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                SYSTEM_DIRECTORY;
17352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        if (userId == 0) {
17452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Leave it in the same place for user 0
17552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return dataSystemDirectory + LOCK_PATTERN_FILE;
17652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } else {
17761f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasani            return  new File(Environment.getUserSystemDirectory(userId), LOCK_PATTERN_FILE)
17861f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasani                    .getAbsolutePath();
17952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
18052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
18152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
18252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private String getLockPasswordFilename(int userId) {
18352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        String dataSystemDirectory =
18452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                android.os.Environment.getDataDirectory().getAbsolutePath() +
18552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                SYSTEM_DIRECTORY;
18652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        if (userId == 0) {
18752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Leave it in the same place for user 0
18852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return dataSystemDirectory + LOCK_PASSWORD_FILE;
18952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } else {
19061f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasani            return  new File(Environment.getUserSystemDirectory(userId), LOCK_PASSWORD_FILE)
19161f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasani                    .getAbsolutePath();
19252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
19352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
19452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
19552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
19652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public boolean havePassword(int userId) throws RemoteException {
19752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        // Do we need a permissions check here?
19852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
19952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return new File(getLockPasswordFilename(userId)).length() > 0;
20052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
20152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
20252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
20352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public boolean havePattern(int userId) throws RemoteException {
20452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        // Do we need a permissions check here?
20552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
20652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return new File(getLockPatternFilename(userId)).length() > 0;
20752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
20852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
20952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
21052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void setLockPattern(byte[] hash, int userId) throws RemoteException {
21152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkWritePermission(userId);
21252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
21352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        writeFile(getLockPatternFilename(userId), hash);
21452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
21552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
21652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
21752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public boolean checkPattern(byte[] hash, int userId) throws RemoteException {
21852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkPasswordReadPermission(userId);
21952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
22052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Read all the bytes from the file
22152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            RandomAccessFile raf = new RandomAccessFile(getLockPatternFilename(userId), "r");
22252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            final byte[] stored = new byte[(int) raf.length()];
22352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            int got = raf.read(stored, 0, stored.length);
22452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            raf.close();
22552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (got <= 0) {
22652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                return true;
22752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
22852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Compare the hash from the file with the entered pattern's hash
22952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return Arrays.equals(stored, hash);
23052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (FileNotFoundException fnfe) {
23152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.e(TAG, "Cannot read file " + fnfe);
23252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return true;
23352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (IOException ioe) {
23452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.e(TAG, "Cannot read file " + ioe);
23552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return true;
23652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
23752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
23852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
23952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
24052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void setLockPassword(byte[] hash, int userId) throws RemoteException {
24152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkWritePermission(userId);
24252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
24352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        writeFile(getLockPasswordFilename(userId), hash);
24452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
24552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
24652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
24752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public boolean checkPassword(byte[] hash, int userId) throws RemoteException {
24852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkPasswordReadPermission(userId);
24952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
25052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
25152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Read all the bytes from the file
25252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            RandomAccessFile raf = new RandomAccessFile(getLockPasswordFilename(userId), "r");
25352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            final byte[] stored = new byte[(int) raf.length()];
25452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            int got = raf.read(stored, 0, stored.length);
25552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            raf.close();
25652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (got <= 0) {
25752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                return true;
25852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
25952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Compare the hash from the file with the entered password's hash
26052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return Arrays.equals(stored, hash);
26152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (FileNotFoundException fnfe) {
26252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.e(TAG, "Cannot read file " + fnfe);
26352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return true;
26452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (IOException ioe) {
26552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.e(TAG, "Cannot read file " + ioe);
26652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            return true;
26752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
26852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
26952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
27052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    @Override
27152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    public void removeUser(int userId) {
27252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        checkWritePermission(userId);
27352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
27452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
27552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
27652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            File file = new File(getLockPasswordFilename(userId));
27752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (file.exists()) {
27852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                file.delete();
27952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
28052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            file = new File(getLockPatternFilename(userId));
28152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (file.exists()) {
28252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                file.delete();
28352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
28452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
28552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.beginTransaction();
28652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.delete(TABLE, COLUMN_USERID + "='" + userId + "'", null);
28752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.setTransactionSuccessful();
28852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } finally {
28952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.endTransaction();
29052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
29152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
29252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
29352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private void writeFile(String name, byte[] hash) {
29452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
29552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Write the hash to file
29652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            RandomAccessFile raf = new RandomAccessFile(name, "rw");
29752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Truncate the file if pattern is null, to clear the lock
29852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (hash == null || hash.length == 0) {
29952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                raf.setLength(0);
30052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            } else {
30152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                raf.write(hash, 0, hash.length);
30252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
30352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            raf.close();
30452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } catch (IOException ioe) {
30552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            Slog.e(TAG, "Error writing to file " + ioe);
30652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
30752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
30852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
30952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private void writeToDb(String key, String value, int userId) {
310d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani        writeToDb(mOpenHelper.getWritableDatabase(), key, value, userId);
311d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani    }
312d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani
313d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani    private void writeToDb(SQLiteDatabase db, String key, String value, int userId) {
31452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        ContentValues cv = new ContentValues();
31552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        cv.put(COLUMN_KEY, key);
31652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        cv.put(COLUMN_USERID, userId);
31752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        cv.put(COLUMN_VALUE, value);
31852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
31952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        db.beginTransaction();
32052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        try {
32152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.delete(TABLE, COLUMN_KEY + "=? AND " + COLUMN_USERID + "=?",
32252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    new String[] {key, Integer.toString(userId)});
32352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.insert(TABLE, null, cv);
32452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.setTransactionSuccessful();
32552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        } finally {
32652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.endTransaction();
32752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
32852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
32952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
33052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private String readFromDb(String key, String defaultValue, int userId) {
33152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        Cursor cursor;
33252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        String result = defaultValue;
33352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
33452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        if ((cursor = db.query(TABLE, COLUMNS_FOR_QUERY,
33552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                COLUMN_USERID + "=? AND " + COLUMN_KEY + "=?",
33652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                new String[] { Integer.toString(userId), key },
33752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                null, null, null)) != null) {
33852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            if (cursor.moveToFirst()) {
33952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                result = cursor.getString(0);
34052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            }
34152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            cursor.close();
34252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
34352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        return result;
34452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
34552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
34652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    class DatabaseHelper extends SQLiteOpenHelper {
34752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        private static final String TAG = "LockSettingsDB";
34852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        private static final String DATABASE_NAME = "locksettings.db";
34952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
35052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        private static final int DATABASE_VERSION = 1;
35152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
35252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        public DatabaseHelper(Context context) {
35352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            super(context, DATABASE_NAME, null, DATABASE_VERSION);
35452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            setWriteAheadLoggingEnabled(true);
35552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
35652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
35752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        private void createTable(SQLiteDatabase db) {
35852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            db.execSQL("CREATE TABLE " + TABLE + " (" +
35952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
36052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    COLUMN_KEY + " TEXT," +
36152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    COLUMN_USERID + " INTEGER," +
36252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    COLUMN_VALUE + " TEXT" +
36352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani                    ");");
36452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
36552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
36652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        @Override
36752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        public void onCreate(SQLiteDatabase db) {
36852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            createTable(db);
369d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani            initializeDefaults(db);
370d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani        }
371d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani
372d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani        private void initializeDefaults(SQLiteDatabase db) {
373d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani            // Get the lockscreen default from a system property, if available
374d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani            boolean lockScreenDisable = SystemProperties.getBoolean("ro.lockscreen.disable.default",
375d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani                    false);
376d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani            if (lockScreenDisable) {
377d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani                writeToDb(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
378d1645f8d0f30709340eb6b6d6da5022bbab77024Amith Yamasani            }
37952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
38052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
38152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        @Override
38252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
38352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani            // Nothing yet
38452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        }
38552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    }
38652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani
38752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani    private static final String[] VALID_SETTINGS = new String[] {
38852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCKOUT_PERMANENT_KEY,
38952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
39052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
39152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.PASSWORD_TYPE_KEY,
39252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
39352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
39452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
39552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCKSCREEN_OPTIONS,
39652c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
39752c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
39852c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
39952c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        LockPatternUtils.PASSWORD_HISTORY_KEY,
40052c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        Secure.LOCK_PATTERN_ENABLED,
40152c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
40252c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        Secure.LOCK_PATTERN_VISIBLE,
40352c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
40452c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani        };
40552c489cd63cca0361f374f7cb392018fabfa8bccAmith Yamasani}
406