/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.development; import android.content.Context; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.service.oemlock.OemLockManager; import android.system.Os; import android.system.OsConstants; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class Enable16kUtils { private static final long PAGE_SIZE = Os.sysconf(OsConstants._SC_PAGESIZE); private static final int PAGE_SIZE_16KB = 16 * 1024; @VisibleForTesting static final String DEV_OPTION_PROPERTY = "ro.product.build.16k_page.enabled"; private static final String TAG = "Enable16kUtils"; /** * @param context uses context to retrieve OEM unlock info * @return true if device is OEM unlocked and factory reset is allowed for user. */ public static boolean isDeviceOEMUnlocked(@NonNull Context context) { // OEM unlock is checked for bootloader, carrier and user. Check all three to ensure // that device is unlocked and it is also allowed by user as well as carrier final OemLockManager oemLockManager = context.getSystemService(OemLockManager.class); final UserManager userManager = context.getSystemService(UserManager.class); if (oemLockManager == null || userManager == null) { Log.e(TAG, "Required services not found on device to check for OEM unlock state."); return false; } // If either of device or carrier is not allowed to unlock, return false if (!oemLockManager.isDeviceOemUnlocked()) { Log.e(TAG, "Device is not OEM unlocked"); return false; } final UserHandle userHandle = UserHandle.of(UserHandle.myUserId()); if (userManager.hasBaseUserRestriction(UserManager.DISALLOW_FACTORY_RESET, userHandle)) { Log.e(TAG, "Factory reset is not allowed for user."); return false; } return true; } /** * @return true if /data partition is ext4 */ public static boolean isDataExt4() { try (BufferedReader br = new BufferedReader(new FileReader("/proc/mounts"))) { String line; while ((line = br.readLine()) != null) { Log.i(TAG, line); final String[] fields = line.split(" "); final String partition = fields[1]; final String fsType = fields[2]; if (partition.equals("/data") && fsType.equals("ext4")) { return true; } } } catch (IOException e) { Log.e(TAG, "Failed to read /proc/mounts"); } return false; } /** * @return returns true if 16KB developer option is available for the device. */ public static boolean is16KbToggleAvailable() { return SystemProperties.getBoolean(DEV_OPTION_PROPERTY, false); } /** * 16kB page-agnostic mode requires /data to be ext4, ro.product.build.16k_page.enabled for * device and Device OEM unlocked. * * @param context is needed to query OEM unlock state * @return true if device is in page-agnostic mode. */ public static boolean isPageAgnosticModeOn(@NonNull Context context) { return is16KbToggleAvailable() && isDeviceOEMUnlocked(context) && isDataExt4(); } /** * @return returns true if current page size is 16KB */ public static boolean isUsing16kbPages() { return PAGE_SIZE == PAGE_SIZE_16KB; } }