summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdnan Begovic <adnan@cyngn.com>2016-01-19 16:13:21 -0800
committerGerrit Code Review <gerrit@cyanogenmod.org>2016-01-22 15:28:25 -0800
commit5f31f27783f19a5cc4368eca3c8005d290a10247 (patch)
treeac50a148702ff5d913fe0e3ad07b9c8375b1711f
parent35671166550919d7db37b2084ca2bc6d9595e71a (diff)
downloadframeworks_base-5f31f27783f19a5cc4368eca3c8005d290a10247.zip
frameworks_base-5f31f27783f19a5cc4368eca3c8005d290a10247.tar.gz
frameworks_base-5f31f27783f19a5cc4368eca3c8005d290a10247.tar.bz2
fw: Fix protected apps implementation.
Currently a protected component could be accessed from any other means other than the launcher, entirely defeating its purpose. Instead, hook into the activity stack supervisor and quelch attempts at invocation of protected components. This implementation also provides feedback to the user on any attempt to start the component when its in a protected state. TICKET: CYNGNOS-84 Change-Id: Ib0165e7504adb08e21e9566c7394b37dffd280d4
-rw-r--r--core/java/android/app/ApplicationPackageManager.java11
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl4
-rw-r--r--core/java/android/content/pm/PackageManager.java7
-rw-r--r--core/res/res/drawable/stat_notify_protected.xml28
-rw-r--r--core/res/res/values/cm_strings.xml3
-rw-r--r--core/res/res/values/cm_symbols.xml4
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageManagerTests.java18
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityManagerService.java64
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java17
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java48
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java9
11 files changed, 213 insertions, 0 deletions
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index c0cd9ec..db4e123 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2046,6 +2046,17 @@ final class ApplicationPackageManager extends PackageManager {
}
}
+ /** @hide */
+ @Override
+ public boolean isComponentProtected(String callingPackage, ComponentName componentName) {
+ try {
+ return mPM.isComponentProtected(callingPackage, componentName, mContext.getUserId());
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to get component protected setting", re);
+ return false;
+ }
+ }
+
@Override
public PackageInstaller getPackageInstaller() {
synchronized (mLock) {
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 7c77f54..6d8b5cb 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -519,4 +519,8 @@ interface IPackageManager {
void updateIconMapping(String pkgName);
ComposedIconInfo getComposedIconInfo();
int processThemeResources(String themePkgName);
+
+ /** Protected Apps */
+ boolean isComponentProtected(in String callingPackage, in ComponentName componentName,
+ int userId);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8928ad3..529d641 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4561,6 +4561,13 @@ public abstract class PackageManager {
public abstract void setComponentProtectedSetting(ComponentName componentName, boolean newState);
/**
+ * Return whether or not a specific component is protected
+ * @hide
+ */
+ public abstract boolean isComponentProtected(String callingPackage,
+ ComponentName componentName);
+
+ /**
* Adds a {@link CrossProfileIntentFilter}. After calling this method all intents sent from the
* user with id sourceUserId can also be be resolved by activities in the user with id
* targetUserId if they match the specified intent filter.
diff --git a/core/res/res/drawable/stat_notify_protected.xml b/core/res/res/drawable/stat_notify_protected.xml
new file mode 100644
index 0000000..d67a348
--- /dev/null
+++ b/core/res/res/drawable/stat_notify_protected.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2016 The CyanogenMod 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M0 0h24v24H0z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" />
+</vector> \ No newline at end of file
diff --git a/core/res/res/values/cm_strings.xml b/core/res/res/values/cm_strings.xml
index 38b98c6..f9bfff1 100644
--- a/core/res/res/values/cm_strings.xml
+++ b/core/res/res/values/cm_strings.xml
@@ -246,4 +246,7 @@
with spaces on either side. [CHAR LIMIT=3] -->
<string name="kg_sub_separator" translatable="false">" | "</string>
+ <!-- Protected Apps Notification -->
+ <string name="notify_package_component_protected_title">Activity launch blocked</string>
+ <string name="notify_package_component_protected_text"><xliff:g id="app_name">%1$s</xliff:g> is protected from being launched. Click to authenticate and launch the application.</string>
</resources>
diff --git a/core/res/res/values/cm_symbols.xml b/core/res/res/values/cm_symbols.xml
index b0a1105..3afb3e7 100644
--- a/core/res/res/values/cm_symbols.xml
+++ b/core/res/res/values/cm_symbols.xml
@@ -149,4 +149,8 @@
<!-- KeyGuard -->
<java-symbol type="string" name="kg_sub_separator" />
+ <!-- Protected Apps -->
+ <java-symbol type="drawable" name="stat_notify_protected" />
+ <java-symbol type="string" name="notify_package_component_protected_title" />
+ <java-symbol type="string" name="notify_package_component_protected_text" />
</resources>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index a4214cf..8b4030a 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -27,6 +27,7 @@ import static android.system.OsConstants.S_IXOTH;
import android.app.PackageInstallObserver;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -3847,4 +3848,21 @@ public class PackageManagerTests extends AndroidTestCase {
* how to do tests on updated system apps?
* verify updates to system apps cannot be installed on the sdcard.
*/
+
+ //CM Tests
+ public void testIsComponentProtectedFromSamePackage() {
+ ComponentName testComponentName = new ComponentName("com.android.test",
+ "com.android.test.component.protected");
+ getPm().setComponentProtectedSetting(testComponentName, true);
+ assertFalse(getPm().isComponentProtected(testComponentName.getPackageName(),
+ testComponentName));
+ }
+
+ public void testIsComponentProtectedFromManagers() {
+ ComponentName testComponentName = new ComponentName("com.android.test",
+ "com.android.test.component.protected");
+ getPm().setComponentProtectedSetting(testComponentName, true);
+ assertFalse(getPm().isComponentProtected(testComponentName.getPackageName(),
+ testComponentName));
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bb61149..b40882d 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1399,6 +1399,7 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 59;
static final int POST_PRIVACY_NOTIFICATION_MSG = 60;
static final int CANCEL_PRIVACY_NOTIFICATION_MSG = 61;
+ static final int POST_COMPONENT_PROTECTED_MSG = 62;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -2167,6 +2168,69 @@ public final class ActivityManagerService extends ActivityManagerNative
} catch (RemoteException e) {
}
} break;
+ case POST_COMPONENT_PROTECTED_MSG: {
+ INotificationManager inm = NotificationManager.getService();
+ if (inm == null) {
+ return;
+ }
+
+ Intent targetIntent = (Intent) msg.obj;
+ if (targetIntent == null) {
+ return;
+ }
+
+ int targetUserId = targetIntent.getIntExtra(
+ "com.android.settings.PROTECTED_APPS_USER_ID", mCurrentUserId);
+ // Resolve for labels and whatnot
+ ActivityInfo root = resolveActivityInfo(targetIntent, targetIntent.getFlags(),
+ targetUserId);
+
+ try {
+ Intent protectedAppIntent = new Intent();
+ protectedAppIntent.setComponent(
+ new ComponentName("com.android.settings",
+ "com.android.settings.applications.ProtectedAppsActivity"));
+ protectedAppIntent.putExtra(
+ "com.android.settings.PROTECTED_APP_TARGET_INTENT",
+ targetIntent);
+ Context context = mContext.createPackageContext("com.android.settings", 0);
+ String title = mContext.getString(
+ com.android.internal.R.string
+ .notify_package_component_protected_title);
+ String text = mContext.getString(
+ com.android.internal.R.string
+ .notify_package_component_protected_text,
+ root.applicationInfo.loadLabel(mContext.getPackageManager()));
+ Notification notification = new Notification.Builder(context)
+ .setSmallIcon(com.android.internal.R.drawable.stat_notify_protected)
+ .setWhen(0)
+ .setTicker(title)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color
+ .system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(text)
+ .setDefaults(Notification.DEFAULT_VIBRATE)
+ .setPriority(Notification.PRIORITY_MAX)
+ .setStyle(new Notification.BigTextStyle().bigText(text))
+ .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
+ protectedAppIntent, PendingIntent.FLAG_CANCEL_CURRENT, null,
+ new UserHandle(mCurrentUserId)))
+ .build();
+ try {
+ int[] outId = new int[1];
+ inm.enqueueNotificationWithTag("android", "android", null,
+ R.string.notify_package_component_protected_title,
+ notification, outId, mCurrentUserId);
+ } catch (RuntimeException e) {
+ Slog.w(ActivityManagerService.TAG,
+ "Error showing notification for protected app component", e);
+ } catch (RemoteException e) {
+ }
+ } catch (NameNotFoundException e) {
+ Slog.w(TAG, "Unable to create context for protected app notification", e);
+ }
+ } break;
}
}
};
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index be90dc8..cb281ec 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -971,6 +971,23 @@ public final class ActivityStackSupervisor implements DisplayListener {
// Cannot start a child activity if the parent is not resumed.
return ActivityManager.START_CANCELED;
}
+
+ try {
+ //TODO: This needs to be a flushed out API in the future.
+ if (AppGlobals.getPackageManager()
+ .isComponentProtected(callingPackage, intent.getComponent(), userId)) {
+ Message msg = mService.mHandler.obtainMessage(
+ ActivityManagerService.POST_COMPONENT_PROTECTED_MSG);
+ //Store start flags, userid
+ intent.setFlags(startFlags);
+ intent.putExtra("com.android.settings.PROTECTED_APPS_USER_ID", userId);
+ msg.obj = intent;
+ mService.mHandler.sendMessage(msg);
+ return ActivityManager.START_NOT_CURRENT_USER_ACTIVITY;
+ }
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
final int realCallingPid = Binder.getCallingPid();
final int realCallingUid = Binder.getCallingUid();
int callingPid;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c1fe38e..4987c9e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -336,6 +336,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private static final boolean DEBUG_DEXOPT = false;
private static final boolean DEBUG_ABI_SELECTION = false;
private static final boolean DEBUG_PREBUNDLED_SCAN = false;
+ private static final boolean DEBUG_PROTECTED = false;
static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
@@ -17195,6 +17196,53 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
+ public boolean isComponentProtected(String callingPackage,
+ ComponentName componentName, int userId) {
+ if (DEBUG_PROTECTED) Log.d(TAG, "Checking if component is protected "
+ + componentName.flattenToShortString() + " from calling package " + callingPackage);
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "set protected");
+
+ //Allow managers full access
+ List<String> protectedComponentManagers =
+ CMSettings.Secure.getDelimitedStringAsList(mContext.getContentResolver(),
+ CMSettings.Secure.PROTECTED_COMPONENT_MANAGERS, "|");
+ if (protectedComponentManagers.contains(callingPackage)) {
+ if (DEBUG_PROTECTED) Log.d(TAG, "Calling package is a protected manager, allow");
+ return false;
+ }
+
+ String packageName = componentName.getPackageName();
+ String className = componentName.getClassName();
+
+ //If this component is launched from the same package, allow it.
+ if (TextUtils.equals(packageName, callingPackage)) {
+ if (DEBUG_PROTECTED) Log.d(TAG, "Calling package is same as target, allow");
+ return false;
+ }
+
+ PackageSetting pkgSetting;
+ ArraySet<String> components;
+
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+
+ if (pkgSetting == null) {
+ if (className == null) {
+ throw new IllegalArgumentException(
+ "Unknown package: " + packageName);
+ }
+ throw new IllegalArgumentException(
+ "Unknown component: " + packageName
+ + "/" + className);
+ }
+ // Get all the protected components
+ components = pkgSetting.getProtectedComponents(userId);
+ if (DEBUG_PROTECTED) Log.d(TAG, "Got " + components.size() + " protected components");
+ return components.size() > 0;
+ }
+ }
+
+ @Override
public boolean isStorageLow() {
final long token = Binder.clearCallingIdentity();
try {
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 7aacb23..d3e2bfd 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -891,6 +891,7 @@ public class MockPackageManager extends PackageManager {
public boolean isUpgrade() {
throw new UnsupportedOperationException();
}
+
/**
* @hide
*/
@@ -903,6 +904,14 @@ public class MockPackageManager extends PackageManager {
* @hide
*/
@Override
+ public boolean isComponentProtected(String callingPackage, ComponentName componentName) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
public void installPackage(Uri packageURI, PackageInstallObserver observer,
int flags, String installerPackageName) {
throw new UnsupportedOperationException();