diff --git a/Android.mk b/Android.mk index 5e47a2ac..532b891f 100644 --- a/Android.mk +++ b/Android.mk @@ -25,7 +25,7 @@ LOCAL_PATH := $(call my-dir) lineage_platform_res := APPS/org.lineageos.platform-res_intermediates/src # List of packages used in lineage-api-stubs -lineage_stub_packages := lineageos.app:lineageos.content:lineageos.hardware:lineageos.media:lineageos.os:lineageos.preference:lineageos.profiles:lineageos.providers:lineageos.platform:lineageos.power:lineageos.util:lineageos.weather:lineageos.weatherservice:lineageos.style +lineage_stub_packages := lineageos.app:lineageos.content:lineageos.hardware:lineageos.media:lineageos.os:lineageos.preference:lineageos.profiles:lineageos.providers:lineageos.platform:lineageos.power:lineageos.util:lineageos.weather:lineageos.weatherservice:lineageos.style:lineageos.trust # The LineageOS Platform Framework Library # ============================================================ diff --git a/api/lineage_current.txt b/api/lineage_current.txt index 9f363065..e9b5e32f 100644 --- a/api/lineage_current.txt +++ b/api/lineage_current.txt @@ -335,6 +335,7 @@ package lineageos.os { field public static final int FIG = 6; // 0x6 field public static final int GUAVA = 7; // 0x7 field public static final int HACKBERRY = 8; // 0x8 + field public static final int ILAMA = 9; // 0x9 } public final class Concierge { @@ -368,6 +369,7 @@ package lineageos.platform { field public static final java.lang.String PROTECTED_APP = "lineageos.permission.PROTECTED_APP"; field public static final java.lang.String READ_DATAUSAGE = "lineageos.permission.READ_DATAUSAGE"; field public static final java.lang.String READ_WEATHER = "lineageos.permission.READ_WEATHER"; + field public static final java.lang.String TRUST_INTERFACE = "lineageos.permission.TRUST_INTERFACE"; field public static final java.lang.String WRITE_DATAUSAGE = "lineageos.permission.WRITE_DATAUSAGE"; field public static final java.lang.String WRITE_SECURE_SETTINGS = "lineageos.permission.WRITE_SECURE_SETTINGS"; field public static final java.lang.String WRITE_SETTINGS = "lineageos.permission.WRITE_SETTINGS"; @@ -775,6 +777,7 @@ package lineageos.providers { method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String); field public static final android.net.Uri CONTENT_URI; field public static final java.lang.String SYS_PROP_LINEAGE_SETTING_VERSION = "sys.lineage_settings_secure_version"; + field public static final java.lang.String TRUST_NOTIFICATIONS = "trust_notifications"; } public static final class LineageSettings.System extends android.provider.Settings.NameValueTable { @@ -1016,6 +1019,27 @@ package lineageos.style { } +package lineageos.trust { + + public class TrustInterface { + method public static lineageos.trust.TrustInterface getInstance(android.content.Context); + method public int getLevelForFeature(int); + method public boolean postNotificationForFeature(int); + method public boolean removeNotificationForFeature(int); + field public static final int ERROR_UNDEFINED = -1; // 0xffffffff + field public static final int TRUST_FEATURE_ENCRYPTION = 4; // 0x4 + field public static final int TRUST_FEATURE_LEVEL_BAD = 2; // 0x2 + field public static final int TRUST_FEATURE_LEVEL_GOOD = 0; // 0x0 + field public static final int TRUST_FEATURE_LEVEL_POOR = 1; // 0x1 + field public static final int TRUST_FEATURE_PLATFORM_SECURITY_PATCH = 2; // 0x2 + field public static final int TRUST_FEATURE_ROOT = 1; // 0x1 + field public static final int TRUST_FEATURE_SELINUX = 0; // 0x0 + field public static final int TRUST_FEATURE_VENDOR_SECURITY_PATCH = 3; // 0x3 + field public static final java.lang.String TRUST_INTERFACE_PERMISSION = "lineageos.permission.TRUST_INTERFACE"; + } + +} + package lineageos.util { public class ColorUtils { diff --git a/lineage/lib/main/java/org/lineageos/platform/internal/TrustInterfaceService.java b/lineage/lib/main/java/org/lineageos/platform/internal/TrustInterfaceService.java new file mode 100644 index 00000000..41956b08 --- /dev/null +++ b/lineage/lib/main/java/org/lineageos/platform/internal/TrustInterfaceService.java @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2018 The LineageOS 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 org.lineageos.platform.internal; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.admin.DevicePolicyManager; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.SELinux; +import android.os.ServiceManager; +import android.os.SystemProperties; +import android.os.UserHandle; +import android.util.Log; +import android.util.Pair; +import android.text.TextUtils; + +import lineageos.app.LineageContextConstants; +import lineageos.providers.LineageSettings; +import lineageos.trust.ITrustInterface; +import lineageos.trust.TrustInterface; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +/** @hide **/ +public class TrustInterfaceService extends LineageSystemService { + private static final String TAG = "LineageTrustInterfaceService"; + private static final String PLATFORM_SECURITY_PATCHES = "ro.build.version.security_patch"; + private static final String VENDOR_SECURITY_PATCHES = "ro.vendor.build.security_patch"; + private static final String LINEAGE_VENDOR_SECURITY_PATCHES = + "ro.lineage.build.vendor_security_patch"; + private static final String INTENT_PARTS = "org.lineageos.lineageparts.TRUST_INTERFACE"; + private static final String INTENT_ONBOARDING = "org.lineageos.lineageparts.TRUST_HINT"; + private static final String CHANNEL_NAME = "TrustInterface"; + private static final int ONBOARDING_NOTIFCATION_ID = 89; + + private Context mContext; + private NotificationManager mNotificationManager = null; + + public TrustInterfaceService(Context context) { + super(context); + mContext = context; + if (context.getPackageManager().hasSystemFeature(LineageContextConstants.Features.TRUST)) { + publishBinderService(LineageContextConstants.LINEAGE_TRUST_INTERFACE, mService); + } else { + Log.wtf(TAG, "Lineage Trust service started by system server but feature xml not" + + " declared. Not publishing binder service!"); + } + } + + @Override + public String getFeatureDeclaration() { + return LineageContextConstants.Features.TRUST; + } + + @Override + public void onStart() { + mNotificationManager = mContext.getSystemService(NotificationManager.class); + // Onboard + if (!hasOnboardedUser()) { + postOnBoardingNotification(); + return; + } + + int selinuxStatus = getSELinuxStatus(); + if (selinuxStatus != TrustInterface.TRUST_FEATURE_LEVEL_GOOD) { + postNotificationForFeatureInternal(TrustInterface.TRUST_FEATURE_SELINUX); + } + } + + /* Public methods implementation */ + + private boolean postNotificationForFeatureInternal(int feature) { + if (!hasOnboardedUser() || !userAllowsTrustNotifications()) { + return false; + } + + Pair strings = getNotificationStringsForFeature(feature); + if (strings == null) { + return false; + } + + String title = mContext.getString(strings.first); + String message = mContext.getString(strings.second); + Intent intent = new Intent(INTENT_PARTS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + PendingIntent pIntent = PendingIntent.getActivity(mContext, 0, intent, 0); + + Notification.Builder notification = new Notification.Builder(mContext, CHANNEL_NAME) + .setContentTitle(title) + .setContentText(message) + .setStyle(new Notification.BigTextStyle().bigText(message)) + .setAutoCancel(true) + .setContentIntent(pIntent) + .setColor(mContext.getColor(R.color.color_error)) + .setSmallIcon(R.drawable.ic_warning); + + createNotificationChannelIfNeeded(); + mNotificationManager.notify(feature, notification.build()); + return true; + } + + private boolean removeNotificationForFeatureInternal(int feature) { + if (!userAllowsTrustNotifications()) { + return false; + } + + mNotificationManager.cancel(feature); + return true; + } + + private boolean postOnBoardingNotification() { + if (hasOnboardedUser()) { + return false; + } + + String title = mContext.getString(R.string.trust_notification_title_onboarding); + String message = mContext.getString(R.string.trust_notification_content_onboarding); + Intent intent = new Intent(INTENT_ONBOARDING); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + PendingIntent pIntent = PendingIntent.getActivity(mContext, 0, intent, 0); + + Notification.Builder notification = new Notification.Builder(mContext, CHANNEL_NAME) + .setContentTitle(title) + .setContentText(message) + .setStyle(new Notification.BigTextStyle().bigText(message)) + .setAutoCancel(true) + .setContentIntent(pIntent) + .setSmallIcon(R.drawable.ic_trust); + + createNotificationChannelIfNeeded(); + mNotificationManager.notify(ONBOARDING_NOTIFCATION_ID, notification.build()); + return true; + } + + private int getLevelForFeatureInternal(int feature) { + switch (feature) { + case TrustInterface.TRUST_FEATURE_SELINUX: + return getSELinuxStatus(); + case TrustInterface.TRUST_FEATURE_ROOT: + return getRootStatus(); + case TrustInterface.TRUST_FEATURE_PLATFORM_SECURITY_PATCH: + return getSecurityPatchStatus(PLATFORM_SECURITY_PATCHES); + case TrustInterface.TRUST_FEATURE_VENDOR_SECURITY_PATCH: + return getSecurityPatchStatus(VENDOR_SECURITY_PATCHES); + case TrustInterface.TRUST_FEATURE_ENCRYPTION: + return getEncryptionStatus(); + default: + return TrustInterface.ERROR_UNDEFINED; + } + } + + /* Utils */ + + private void enforceTrustPermission() { + mContext.enforceCallingOrSelfPermission(TrustInterface.TRUST_INTERFACE_PERMISSION, + "You do not have permissions to use the Trust interface"); + } + + private boolean userAllowsTrustNotifications() { + return LineageSettings.Secure.getInt(mContext.getContentResolver(), + LineageSettings.Secure.TRUST_NOTIFICATIONS, 1) == 1; + } + + private Pair getNotificationStringsForFeature(int feature) { + int title = 0; + int message = 0; + + switch (feature) { + case TrustInterface.TRUST_FEATURE_SELINUX: + title = R.string.trust_notification_title_selinux; + message = R.string.trust_notification_content_selinux; + break; + case TrustInterface.TRUST_FEATURE_ROOT: + title = R.string.trust_notification_title_root; + message = R.string.trust_notification_content_root; + break; + } + + return title == 0 ? null : new Pair(title, message); + } + + private void createNotificationChannelIfNeeded() { + NotificationChannel channel = mNotificationManager.getNotificationChannel(CHANNEL_NAME); + if (channel != null) { + return; + } + + String name = mContext.getString(R.string.trust_notification_channel); + int importance = NotificationManager.IMPORTANCE_HIGH; + NotificationChannel trustChannel = new NotificationChannel(CHANNEL_NAME, + name, importance); + trustChannel.setBlockableSystem(true); + mNotificationManager.createNotificationChannel(trustChannel); + } + + private int getSELinuxStatus() { + return SELinux.isSELinuxEnforced() ? + TrustInterface.TRUST_FEATURE_LEVEL_GOOD : + TrustInterface.TRUST_FEATURE_LEVEL_BAD; + } + + private int getRootStatus() { + String status = SystemProperties.get("persist.sys.root_access"); + switch (status) { + case "0": + return TrustInterface.TRUST_FEATURE_LEVEL_GOOD; + case "1": + case "3": + return TrustInterface.TRUST_FEATURE_LEVEL_BAD; + case "2": + return TrustInterface.TRUST_FEATURE_LEVEL_POOR; + default: + return TrustInterface.ERROR_UNDEFINED; + } + } + + private int getSecurityPatchStatus(String target) { + String patchLevel = SystemProperties.get(target); + if (TextUtils.isEmpty(patchLevel)) { + // Try to fallback to Lineage vendor prop + if (VENDOR_SECURITY_PATCHES.equals(target)) { + patchLevel = SystemProperties.get(LINEAGE_VENDOR_SECURITY_PATCHES); + if (TextUtils.isEmpty(patchLevel)) { + return TrustInterface.ERROR_UNDEFINED; + } + } else { + return TrustInterface.ERROR_UNDEFINED; + } + } + + Calendar today = Calendar.getInstance(); + Calendar patchCal = Calendar.getInstance(); + + try { + Date date = new SimpleDateFormat("yyyy-MM-dd").parse(patchLevel); + patchCal.setTime(date); + + int diff = (today.get(Calendar.YEAR) - patchCal.get(Calendar.YEAR)) * 12 + + today.get(Calendar.MONTH) - patchCal.get(Calendar.MONTH); + if (diff < 0) { + // This is a blatant lie + return TrustInterface.TRUST_FEATURE_LEVEL_BAD; + } else if (diff < 6) { + return TrustInterface.TRUST_FEATURE_LEVEL_GOOD; + } else if (diff < 12) { + return TrustInterface.TRUST_FEATURE_LEVEL_POOR; + } + return TrustInterface.TRUST_FEATURE_LEVEL_BAD; + } catch (ParseException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return TrustInterface.ERROR_UNDEFINED; + } + + private int getEncryptionStatus() { + DevicePolicyManager policyManager = mContext.getSystemService(DevicePolicyManager.class); + if (policyManager == null) { + return TrustInterface.ERROR_UNDEFINED; + } + + boolean isOldDevice = + mContext.getResources().getBoolean(R.bool.config_trustLegacyEncryption); + int status = policyManager.getStorageEncryptionStatus(); + + switch (status) { + case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE: + case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER: + return TrustInterface.TRUST_FEATURE_LEVEL_GOOD; + case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY: + return TrustInterface.TRUST_FEATURE_LEVEL_POOR; + case DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE: + return isOldDevice ? + TrustInterface.TRUST_FEATURE_LEVEL_POOR : + TrustInterface.TRUST_FEATURE_LEVEL_BAD; + default: + return TrustInterface.ERROR_UNDEFINED; + } + } + + private boolean hasOnboardedUser() { + return LineageSettings.System.getInt(mContext.getContentResolver(), + LineageSettings.System.TRUST_INTERFACE_HINTED, 0) == 1; + } + + /* Service */ + + private final IBinder mService = new ITrustInterface.Stub() { + @Override + public boolean postNotificationForFeature(int feature) { + enforceTrustPermission(); + /* + * We need to clear the caller's identity in order to + * allow this method call to modify settings + * not allowed by the caller's permissions. + */ + long token = clearCallingIdentity(); + boolean success = postNotificationForFeatureInternal(feature); + restoreCallingIdentity(token); + return success; + } + + @Override + public boolean removeNotificationForFeature(int feature) { + enforceTrustPermission(); + /* + * We need to clear the caller's identity in order to + * allow this method call to modify settings + * not allowed by the caller's permissions. + */ + long token = clearCallingIdentity(); + boolean success = removeNotificationForFeatureInternal(feature); + restoreCallingIdentity(token); + return success; + } + + @Override + public int getLevelForFeature(int feature) { + /* + * No need to require permission for this one because it's harmless + */ + return getLevelForFeatureInternal(feature); + } + }; +} \ No newline at end of file diff --git a/lineage/res/AndroidManifest.xml b/lineage/res/AndroidManifest.xml index f3a5346a..aa4e0f59 100644 --- a/lineage/res/AndroidManifest.xml +++ b/lineage/res/AndroidManifest.xml @@ -124,6 +124,13 @@ android:icon="@drawable/ic_launcher_lineageos" android:protectionLevel="dangerous" /> + + + + + + + \ No newline at end of file diff --git a/lineage/res/res/drawable/ic_warning.xml b/lineage/res/res/drawable/ic_warning.xml new file mode 100644 index 00000000..e711b296 --- /dev/null +++ b/lineage/res/res/drawable/ic_warning.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/lineage/res/res/values/colors.xml b/lineage/res/res/values/colors.xml new file mode 100644 index 00000000..8ff675b2 --- /dev/null +++ b/lineage/res/res/values/colors.xml @@ -0,0 +1,20 @@ + + + + + #FF5630 + diff --git a/lineage/res/res/values/config.xml b/lineage/res/res/values/config.xml index 32257b25..1faefa98 100644 --- a/lineage/res/res/values/config.xml +++ b/lineage/res/res/values/config.xml @@ -109,6 +109,7 @@ org.lineageos.platform.internal.display.LiveDisplayService org.lineageos.platform.internal.LineageAudioService org.lineageos.platform.internal.StyleInterfaceService + org.lineageos.platform.internal.TrustInterfaceService @@ -235,4 +236,8 @@ platform signatures, specifically for use on devices with a vendor partition. --> + + + false diff --git a/lineage/res/res/values/strings.xml b/lineage/res/res/values/strings.xml index 43fd1417..f44ed0ca 100644 --- a/lineage/res/res/values/strings.xml +++ b/lineage/res/res/values/strings.xml @@ -176,4 +176,20 @@ Lavender Tomato Banana + + + + Trust + access Trust interface + Allows an app to display Trust warnings and suggestions + Trust alerts + Trust \u2022 System security + SELinux is not enforcing, your security has been weakened + Trust \u2022 Root access + An app is using the root privileges right now + Discover Trust + Get to know how to assure your device is safe + Not now diff --git a/lineage/res/res/values/symbols.xml b/lineage/res/res/values/symbols.xml index 1bf265ce..0e8f6243 100644 --- a/lineage/res/res/values/symbols.xml +++ b/lineage/res/res/values/symbols.xml @@ -162,4 +162,21 @@ + + + + + + + + + + + + + + + + + diff --git a/sdk/src/java/lineageos/app/LineageContextConstants.java b/sdk/src/java/lineageos/app/LineageContextConstants.java index 640e308b..33fd85bb 100644 --- a/sdk/src/java/lineageos/app/LineageContextConstants.java +++ b/sdk/src/java/lineageos/app/LineageContextConstants.java @@ -107,6 +107,17 @@ public final class LineageContextConstants { */ public static final String LINEAGE_STYLE_INTERFACE = "lineagestyle"; + /** + * Use with {@link android.content.Context#getSystemService} to retrieve a + * {@link lineageos.trust.TrustInterface} to access the Trust interface. + * + * @see android.content.Context#getSystemService + * @see lineageos.trust.TrustInterface + * + * @hide + */ + public static final String LINEAGE_TRUST_INTERFACE = "lineagetrust"; + /** * Features supported by the Lineage SDK. */ @@ -166,5 +177,13 @@ public final class LineageContextConstants { */ @SdkConstant(SdkConstant.SdkConstantType.FEATURE) public static final String STYLES = "org.lineageos.style"; + + /** + * Feature for {@link PackageManager#getSystemAvailableFeatures} and + * {@link PackageManager#hasSystemFeature}: The device includes the lineage trust service + * utilized by the lineage sdk. + */ + @SdkConstant(SdkConstant.SdkConstantType.FEATURE) + public static final String TRUST = "org.lineageos.trust"; } } diff --git a/sdk/src/java/lineageos/providers/LineageSettings.java b/sdk/src/java/lineageos/providers/LineageSettings.java index ac48c996..81dbb738 100644 --- a/sdk/src/java/lineageos/providers/LineageSettings.java +++ b/sdk/src/java/lineageos/providers/LineageSettings.java @@ -79,6 +79,16 @@ public final class LineageSettings { public static final String ACTION_LIVEDISPLAY_SETTINGS = "lineageos.settings.LIVEDISPLAY_SETTINGS"; + /** + * Activity Action: Show Trust interface settings + *

+ * Input: Nothing. + *

+ * Output: Nothing. + */ + public static final String ACTION_TRUST_INTERFACE = + "lineageos.settings.TRUST_INTERFACE"; + // region Call Methods /** @@ -1528,6 +1538,15 @@ public final class LineageSettings { public static final Validator LIVE_DISPLAY_HINTED_VALIDATOR = new InclusiveIntegerRangeValidator(-3, 1); + /** + * Did we tell the user about the trust brand and interface? + * @hide + */ + public static final String TRUST_INTERFACE_HINTED = "trust_interface_hinted"; + + /** @hide */ + public static final Validator TRUST_INTERFACE_HINTED_VALIDATOR = sBooleanValidator; + /** * Enable statusbar double tap gesture on to put device to sleep * 0 = 0ff, 1 = on @@ -1550,7 +1569,7 @@ public final class LineageSettings { /** * Show search bar in recents - * 0 = 0ff, 1 = on + * 0 = Off, 1 = on */ public static final String RECENTS_SHOW_SEARCH_BAR = "recents_show_search_bar"; @@ -2232,6 +2251,7 @@ public final class LineageSettings { VALIDATORS.put(DISPLAY_COLOR_ENHANCE, DISPLAY_COLOR_ENHANCE_VALIDATOR); VALIDATORS.put(DISPLAY_COLOR_ADJUSTMENT, DISPLAY_COLOR_ADJUSTMENT_VALIDATOR); VALIDATORS.put(LIVE_DISPLAY_HINTED, LIVE_DISPLAY_HINTED_VALIDATOR); + VALIDATORS.put(TRUST_INTERFACE_HINTED, TRUST_INTERFACE_HINTED_VALIDATOR); VALIDATORS.put(DOUBLE_TAP_SLEEP_GESTURE, DOUBLE_TAP_SLEEP_GESTURE_VALIDATOR); VALIDATORS.put(STATUS_BAR_SHOW_WEATHER, STATUS_BAR_SHOW_WEATHER_VALIDATOR); VALIDATORS.put(RECENTS_SHOW_SEARCH_BAR, RECENTS_SHOW_SEARCH_BAR_VALIDATOR); @@ -3019,6 +3039,16 @@ public final class LineageSettings { /** @hide */ public static final Validator NETWORK_TRAFFIC_SHOW_UNITS_VALIDATOR = sBooleanValidator; + /** + * Enable displaying the Trust service's notifications + * 0 = 0ff, 1 = on + */ + public static final String TRUST_NOTIFICATIONS = "trust_notifications"; + + /** @hide */ + public static final Validator TRUST_NOTIFICATIONS_VALIDATOR = + sBooleanValidator; + // endregion /** @@ -3128,6 +3158,7 @@ public final class LineageSettings { VALIDATORS.put(NETWORK_TRAFFIC_AUTOHIDE, NETWORK_TRAFFIC_AUTOHIDE_VALIDATOR); VALIDATORS.put(NETWORK_TRAFFIC_UNITS, NETWORK_TRAFFIC_UNITS_VALIDATOR); VALIDATORS.put(NETWORK_TRAFFIC_SHOW_UNITS, NETWORK_TRAFFIC_SHOW_UNITS_VALIDATOR); + VALIDATORS.put(TRUST_NOTIFICATIONS, TRUST_NOTIFICATIONS_VALIDATOR); } /** diff --git a/sdk/src/java/lineageos/trust/ITrustInterface.aidl b/sdk/src/java/lineageos/trust/ITrustInterface.aidl new file mode 100644 index 00000000..385d8e0e --- /dev/null +++ b/sdk/src/java/lineageos/trust/ITrustInterface.aidl @@ -0,0 +1,26 @@ +/* +** +** Copyright (C) 2018 The LineageOS 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 lineageos.trust; + +/** {@hide} */ +interface ITrustInterface { + + boolean postNotificationForFeature(int feature); + boolean removeNotificationForFeature(int feature); + int getLevelForFeature(int feature); +} diff --git a/sdk/src/java/lineageos/trust/TrustInterface.java b/sdk/src/java/lineageos/trust/TrustInterface.java new file mode 100644 index 00000000..9f3c7d8d --- /dev/null +++ b/sdk/src/java/lineageos/trust/TrustInterface.java @@ -0,0 +1,217 @@ +/** + * Copyright (c) 2015, The LineageOS 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 lineageos.trust; + +import android.content.Context; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +import lineageos.app.LineageContextConstants; + +public class TrustInterface { + /** + * Allows an application to use the Trust interface to display trusted + * security messages to the user. + * This is a system-only permission, user-installed apps cannot use it + */ + public static final String TRUST_INTERFACE_PERMISSION = "lineageos.permission.TRUST_INTERFACE"; + + /** + * Unable to determine status, an error occured + * + * @see #getLevelForFeature + */ + public static final int ERROR_UNDEFINED = -1; + + /** + * Trust feature status: good. The feature is in a configuration + * that will help protect the user's data + * + * @see #getLevelForFeature + */ + public static final int TRUST_FEATURE_LEVEL_GOOD = 0; + + /** + * Trust feature status: poor. The feature is in a configuration + * that might be used to harm the user's data + * + * @see #getLevelForFeature + */ + public static final int TRUST_FEATURE_LEVEL_POOR = 1; + + /** + * Trust feature status: bad. The feature is in a configuration + * that is dangerous for the user's data + * + * @see #getLevelForFeature + */ + public static final int TRUST_FEATURE_LEVEL_BAD = 2; + + /** + * Trust feature indicator: SELinux status + * + * Possible status: + * * {@link #TRUST_FEATURE_LEVEL_GOOD}: enforcing + * * {@link #TRUST_FEATURE_LEVEL_BAD}: permissive / disabled + * + * @see #getLevelForFeature + */ + public static final int TRUST_FEATURE_SELINUX = 0; + + /** + * Trust feature indicator: Root access + * + * Possible status: + * * {@link #TRUST_FEATURE_LEVEL_GOOD}: disabled + * * {@link #TRUST_FEATURE_LEVEL_POOR}: ADB only + * * {@link #TRUST_FEATURE_LEVEL_BAD}: apps and ADB + * + * @see #getLevelForFeature + */ + public static final int TRUST_FEATURE_ROOT = 1; + + /** + * Trust feature indicator: Platform Security patches + * + * Possible status: + * * {@link #TRUST_FEATURE_LEVEL_GOOD}: less than 3 months old + * * {@link #TRUST_FEATURE_LEVEL_POOR}: less than 9 months old + * * {@link #TRUST_FEATURE_LEVEL_BAD}: older than 9 months + * + * @see #getLevelForFeature + */ + public static final int TRUST_FEATURE_PLATFORM_SECURITY_PATCH = 2; + + /** + * Trust feature indicator: Vendor Security patches + * + * Possible status: + * * {@link #TRUST_FEATURE_LEVEL_GOOD}: less than 3 months old + * * {@link #TRUST_FEATURE_LEVEL_POOR}: less than 9 months old + * * {@link #TRUST_FEATURE_LEVEL_BAD}: older than 9 months + * + * @see #getLevelForFeature + */ + public static final int TRUST_FEATURE_VENDOR_SECURITY_PATCH = 3; + + /** + * Trust feature indicator: Encryption + * + * Some older devices have a significant performance loss when running + * encrypted, so the status will be different when Trust is executed on + * these devices. + * + * Possible status for old device: + * * {@link #TRUST_FEATURE_LEVEL_GOOD}: enabled + * * {@link #TRUST_FEATURE_LEVEL_POOR}: disabled + * + * Possible status for recent device: + * * {@link #TRUST_FEATURE_LEVEL_GOOD}: enabled + * * {@link #TRUST_FEATURE_LEVEL_BAD}: disabled + * + * @see #getLevelForFeature + */ + public static final int TRUST_FEATURE_ENCRYPTION = 4; + + private static final String TAG = "TrustInterface"; + + private static ITrustInterface sService; + private static TrustInterface sInstance; + + private Context mContext; + + private TrustInterface(Context context) { + Context appContext = context.getApplicationContext(); + mContext = appContext == null ? context : appContext; + sService = getService(); + if (context.getPackageManager().hasSystemFeature( + LineageContextConstants.Features.TRUST) && sService == null) { + throw new RuntimeException("Unable to get TrustInterfaceService. The service" + + " either crashed, was not started, or the interface has been called to early" + + " in SystemServer init"); + } + } + + /** + * Get or create an instance of the {@link lineageos.trust.TrustInterface} + * + * @param context Used to get the service + * @return {@link TrustInterface} + */ + public static TrustInterface getInstance(Context context) { + if (sInstance == null) { + sInstance = new TrustInterface(context); + } + return sInstance; + } + + /** @hide **/ + public static ITrustInterface getService() { + if (sService != null) { + return sService; + } + IBinder b = ServiceManager.getService(LineageContextConstants.LINEAGE_TRUST_INTERFACE); + sService = ITrustInterface.Stub.asInterface(b); + + if (b == null) { + Log.e(TAG, "null service. SAD!"); + return null; + } + + sService = ITrustInterface.Stub.asInterface(b); + return sService; + } + + public boolean postNotificationForFeature(int feature) { + if (sService == null) { + return false; + } + try { + return sService.postNotificationForFeature(feature); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return false; + } + + public boolean removeNotificationForFeature(int feature) { + if (sService == null) { + return false; + } + try { + return sService.removeNotificationForFeature(feature); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return false; + } + + public int getLevelForFeature(int feature) { + if (sService == null) { + return ERROR_UNDEFINED; + } + try { + return sService.getLevelForFeature(feature); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return ERROR_UNDEFINED; + } +} +