From d530a1cf56d6cbd927f3d74feaa5a659e5e92225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 26 Aug 2015 15:44:41 +0200 Subject: [PATCH 01/10] Restructure installer packages --- F-Droid/AndroidManifest.xml | 6 +-- .../res/layout-v11/app_permission_item.xml | 2 +- F-Droid/res/layout/app_permission_item.xml | 2 +- .../res/layout/app_permission_item_money.xml | 2 +- F-Droid/res/layout/permissions_list.xml | 4 +- .../content/pm/IPackageDeleteObserver.java | 49 ------------------- .../content/pm/IPackageInstallObserver.java | 49 ------------------- F-Droid/src/org/fdroid/fdroid/FDroid.java | 5 +- ...rSdk14.java => DefaultSdk14Installer.java} | 4 +- .../fdroid/fdroid/installer/Installer.java | 4 +- ...nstaller.java => PrivilegedInstaller.java} | 19 ++++--- .../install/InstallPrivileged.java} | 14 +++--- .../InstallPrivilegedBootReceiver.java} | 8 +-- .../InstallPrivilegedDialogActivity.java} | 45 ++++++++--------- .../views}/AppDiff.java | 8 +-- .../views}/AppSecurityPermissions.java | 2 +- .../views}/CaffeinatedScrollView.java | 2 +- .../views}/InstallConfirmActivity.java | 2 +- .../views}/TabsAdapter.java | 2 +- .../views/fragments/PreferencesFragment.java | 10 ++-- 20 files changed, 72 insertions(+), 167 deletions(-) delete mode 100644 F-Droid/src/android/content/pm/IPackageDeleteObserver.java delete mode 100644 F-Droid/src/android/content/pm/IPackageInstallObserver.java rename F-Droid/src/org/fdroid/fdroid/installer/{DefaultInstallerSdk14.java => DefaultSdk14Installer.java} (97%) rename F-Droid/src/org/fdroid/fdroid/installer/{SystemInstaller.java => PrivilegedInstaller.java} (97%) rename F-Droid/src/org/fdroid/fdroid/{installer/InstallIntoSystem.java => privileged/install/InstallPrivileged.java} (94%) rename F-Droid/src/org/fdroid/fdroid/{installer/InstallIntoSystemBootReceiver.java => privileged/install/InstallPrivilegedBootReceiver.java} (86%) rename F-Droid/src/org/fdroid/fdroid/{installer/InstallIntoSystemDialogActivity.java => privileged/install/InstallPrivilegedDialogActivity.java} (91%) rename F-Droid/src/org/fdroid/fdroid/{installer => privileged/views}/AppDiff.java (94%) rename F-Droid/src/org/fdroid/fdroid/{installer => privileged/views}/AppSecurityPermissions.java (99%) rename F-Droid/src/org/fdroid/fdroid/{installer => privileged/views}/CaffeinatedScrollView.java (98%) rename F-Droid/src/org/fdroid/fdroid/{installer => privileged/views}/InstallConfirmActivity.java (99%) rename F-Droid/src/org/fdroid/fdroid/{installer => privileged/views}/TabsAdapter.java (99%) diff --git a/F-Droid/AndroidManifest.xml b/F-Droid/AndroidManifest.xml index 779fba7e1..60a124616 100644 --- a/F-Droid/AndroidManifest.xml +++ b/F-Droid/AndroidManifest.xml @@ -302,7 +302,7 @@ android:value=".SearchResults" /> + android:name=".privileged.install.InstallPrivilegedBootReceiver" > diff --git a/F-Droid/res/layout-v11/app_permission_item.xml b/F-Droid/res/layout-v11/app_permission_item.xml index b5aab370d..0cb5e3405 100644 --- a/F-Droid/res/layout-v11/app_permission_item.xml +++ b/F-Droid/res/layout-v11/app_permission_item.xml @@ -18,7 +18,7 @@ Defines the layout of a single permission item. --> - - - - @@ -50,4 +50,4 @@ This is the structure for the list of all permissions. android:text="@string/devicePerms" /> - + diff --git a/F-Droid/src/android/content/pm/IPackageDeleteObserver.java b/F-Droid/src/android/content/pm/IPackageDeleteObserver.java deleted file mode 100644 index 0c4c6857c..000000000 --- a/F-Droid/src/android/content/pm/IPackageDeleteObserver.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -package android.content.pm; - -/** - * Just a non-working implementation of this Stub to satisfy compiler! - */ -public interface IPackageDeleteObserver extends android.os.IInterface { - - abstract class Stub extends android.os.Binder implements - android.content.pm.IPackageDeleteObserver { - public Stub() { - throw new RuntimeException("Stub!"); - } - - public static android.content.pm.IPackageDeleteObserver asInterface(android.os.IBinder obj) { - throw new RuntimeException("Stub!"); - } - - public android.os.IBinder asBinder() { - throw new RuntimeException("Stub!"); - } - - public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, - int flags) throws android.os.RemoteException { - throw new RuntimeException("Stub!"); - } - } - - void packageDeleted(java.lang.String packageName, int returnCode) - throws android.os.RemoteException; -} diff --git a/F-Droid/src/android/content/pm/IPackageInstallObserver.java b/F-Droid/src/android/content/pm/IPackageInstallObserver.java deleted file mode 100644 index 689198afd..000000000 --- a/F-Droid/src/android/content/pm/IPackageInstallObserver.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -package android.content.pm; - -/** - * Just a non-working implementation of this Stub to satisfy compiler! - */ -public interface IPackageInstallObserver extends android.os.IInterface { - - abstract class Stub extends android.os.Binder implements - android.content.pm.IPackageInstallObserver { - public Stub() { - throw new RuntimeException("Stub!"); - } - - public static android.content.pm.IPackageInstallObserver asInterface(android.os.IBinder obj) { - throw new RuntimeException("Stub!"); - } - - public android.os.IBinder asBinder() { - throw new RuntimeException("Stub!"); - } - - public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, - int flags) throws android.os.RemoteException { - throw new RuntimeException("Stub!"); - } - } - - void packageInstalled(java.lang.String packageName, int returnCode) - throws android.os.RemoteException; -} \ No newline at end of file diff --git a/F-Droid/src/org/fdroid/fdroid/FDroid.java b/F-Droid/src/org/fdroid/fdroid/FDroid.java index 80346c758..36a502734 100644 --- a/F-Droid/src/org/fdroid/fdroid/FDroid.java +++ b/F-Droid/src/org/fdroid/fdroid/FDroid.java @@ -34,7 +34,6 @@ import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBarActivity; import android.support.v7.app.AlertDialog; import android.text.TextUtils; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -45,7 +44,7 @@ import android.widget.Toast; import org.fdroid.fdroid.compat.TabManager; import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.NewRepoConfig; -import org.fdroid.fdroid.installer.InstallIntoSystemDialogActivity; +import org.fdroid.fdroid.privileged.install.InstallPrivilegedDialogActivity; import org.fdroid.fdroid.views.AppListFragmentPagerAdapter; import org.fdroid.fdroid.views.ManageReposActivity; import org.fdroid.fdroid.views.swap.SwapWorkflowActivity; @@ -99,7 +98,7 @@ public class FDroid extends ActionBarActivity { Uri uri = AppProvider.getContentUri(); getContentResolver().registerContentObserver(uri, true, new AppObserver()); - InstallIntoSystemDialogActivity.firstTime(this); + InstallPrivilegedDialogActivity.firstTime(this); } @Override diff --git a/F-Droid/src/org/fdroid/fdroid/installer/DefaultInstallerSdk14.java b/F-Droid/src/org/fdroid/fdroid/installer/DefaultSdk14Installer.java similarity index 97% rename from F-Droid/src/org/fdroid/fdroid/installer/DefaultInstallerSdk14.java rename to F-Droid/src/org/fdroid/fdroid/installer/DefaultSdk14Installer.java index 3373e65ef..ba64aaedb 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/DefaultInstallerSdk14.java +++ b/F-Droid/src/org/fdroid/fdroid/installer/DefaultSdk14Installer.java @@ -39,10 +39,10 @@ import java.util.List; * unattended installations. */ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) -public class DefaultInstallerSdk14 extends Installer { +public class DefaultSdk14Installer extends Installer { private final Activity mActivity; - public DefaultInstallerSdk14(Activity activity, PackageManager pm, InstallerCallback callback) + public DefaultSdk14Installer(Activity activity, PackageManager pm, InstallerCallback callback) throws AndroidNotCompatibleException { super(activity, pm, callback); this.mActivity = activity; diff --git a/F-Droid/src/org/fdroid/fdroid/installer/Installer.java b/F-Droid/src/org/fdroid/fdroid/installer/Installer.java index de9c8ff6f..7eb69a6d5 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/Installer.java +++ b/F-Droid/src/org/fdroid/fdroid/installer/Installer.java @@ -113,7 +113,7 @@ abstract public class Installer { Utils.DebugLog(TAG, "system permissions -> SystemInstaller"); try { - return new SystemInstaller(activity, pm, callback); + return new PrivilegedInstaller(activity, pm, callback); } catch (AndroidNotCompatibleException e) { Log.e(TAG, "Android not compatible with SystemInstaller!", e); } @@ -128,7 +128,7 @@ abstract public class Installer { try { Utils.DebugLog(TAG, "try default installer for Android >= 4"); - return new DefaultInstallerSdk14(activity, pm, callback); + return new DefaultSdk14Installer(activity, pm, callback); } catch (AndroidNotCompatibleException e) { Log.e(TAG, "Android not compatible with DefaultInstallerSdk14!", e); } diff --git a/F-Droid/src/org/fdroid/fdroid/installer/SystemInstaller.java b/F-Droid/src/org/fdroid/fdroid/installer/PrivilegedInstaller.java similarity index 97% rename from F-Droid/src/org/fdroid/fdroid/installer/SystemInstaller.java rename to F-Droid/src/org/fdroid/fdroid/installer/PrivilegedInstaller.java index da779c52a..9e1fc047e 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/SystemInstaller.java +++ b/F-Droid/src/org/fdroid/fdroid/installer/PrivilegedInstaller.java @@ -34,6 +34,9 @@ import android.util.Log; import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; +import org.fdroid.fdroid.privileged.views.AppDiff; +import org.fdroid.fdroid.privileged.views.AppSecurityPermissions; +import org.fdroid.fdroid.privileged.views.InstallConfirmActivity; import java.io.File; import java.lang.reflect.Method; @@ -63,20 +66,20 @@ import java.util.List; * https://android.googlesource.com/platform * /frameworks/base/+/ccbf84f44c9e6a5ed3c08673614826bb237afc54 */ -public class SystemInstaller extends Installer { +public class PrivilegedInstaller extends Installer { - private static final String TAG = "SystemInstaller"; + private static final String TAG = "PrivilegedInstaller"; private Activity mActivity; - private final PackageInstallObserver mInstallObserver; - private final PackageDeleteObserver mDeleteObserver; - private Method mInstallMethod; - private Method mDeleteMethod; +// private final PackageInstallObserver mInstallObserver; +// private final PackageDeleteObserver mDeleteObserver; +// private Method mInstallMethod; +// private Method mDeleteMethod; public static final int REQUEST_CONFIRM_PERMS = 0; - public SystemInstaller(Activity activity, PackageManager pm, - InstallerCallback callback) throws AndroidNotCompatibleException { + public PrivilegedInstaller(Activity activity, PackageManager pm, + InstallerCallback callback) throws AndroidNotCompatibleException { super(activity, pm, callback); this.mActivity = activity; diff --git a/F-Droid/src/org/fdroid/fdroid/installer/InstallIntoSystem.java b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java similarity index 94% rename from F-Droid/src/org/fdroid/fdroid/installer/InstallIntoSystem.java rename to F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java index e7fd19643..0b7d13bd3 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/InstallIntoSystem.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java @@ -17,7 +17,7 @@ * MA 02110-1301, USA. */ -package org.fdroid.fdroid.installer; +package org.fdroid.fdroid.privileged.install; import android.content.Context; import android.os.Build; @@ -35,15 +35,15 @@ import eu.chainfire.libsuperuser.Shell; * http://omerjerk.in/2014/08/how-to-install-an-app-to-system-partition/ * https://github.com/omerjerk/RemoteDroid/blob/master/app/src/main/java/in/omerjerk/remotedroid/app/MainActivity.java */ -abstract class InstallIntoSystem { +abstract class InstallPrivileged { protected final Context context; - public InstallIntoSystem(final Context context) { + public InstallPrivileged(final Context context) { this.context = context; } - public static InstallIntoSystem create(final Context context) { + public static InstallPrivileged create(final Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return new LollipopImpl(context); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { @@ -112,7 +112,7 @@ abstract class InstallIntoSystem { return commands; } - private static class PreKitKatImpl extends InstallIntoSystem { + private static class PreKitKatImpl extends InstallPrivileged { public PreKitKatImpl(Context context) { super(context); @@ -125,7 +125,7 @@ abstract class InstallIntoSystem { } - private static class KitKatToLollipopImpl extends InstallIntoSystem { + private static class KitKatToLollipopImpl extends InstallPrivileged { public KitKatToLollipopImpl(Context context) { super(context); @@ -146,7 +146,7 @@ abstract class InstallIntoSystem { * History of PackageManagerService in Lollipop: * https://github.com/android/platform_frameworks_base/commits/lollipop-release/services/core/java/com/android/server/pm/PackageManagerService.java */ - private static class LollipopImpl extends InstallIntoSystem { + private static class LollipopImpl extends InstallPrivileged { public LollipopImpl(Context context) { super(context); diff --git a/F-Droid/src/org/fdroid/fdroid/installer/InstallIntoSystemBootReceiver.java b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedBootReceiver.java similarity index 86% rename from F-Droid/src/org/fdroid/fdroid/installer/InstallIntoSystemBootReceiver.java rename to F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedBootReceiver.java index 42f7e57cc..7f8598243 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/InstallIntoSystemBootReceiver.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedBootReceiver.java @@ -17,7 +17,7 @@ * MA 02110-1301, USA. */ -package org.fdroid.fdroid.installer; +package org.fdroid.fdroid.privileged.install; import android.content.BroadcastReceiver; import android.content.Context; @@ -25,7 +25,7 @@ import android.content.Intent; import org.fdroid.fdroid.Preferences; -public class InstallIntoSystemBootReceiver extends BroadcastReceiver { +public class InstallPrivilegedBootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { @@ -33,8 +33,8 @@ public class InstallIntoSystemBootReceiver extends BroadcastReceiver { if (Preferences.get().isPostSystemInstall()) { Preferences.get().setPostSystemInstall(false); - Intent postInstall = new Intent(context.getApplicationContext(), InstallIntoSystemDialogActivity.class); - postInstall.setAction(InstallIntoSystemDialogActivity.ACTION_POST_INSTALL); + Intent postInstall = new Intent(context.getApplicationContext(), InstallPrivilegedDialogActivity.class); + postInstall.setAction(InstallPrivilegedDialogActivity.ACTION_POST_INSTALL); postInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(postInstall); } diff --git a/F-Droid/src/org/fdroid/fdroid/installer/InstallIntoSystemDialogActivity.java b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java similarity index 91% rename from F-Droid/src/org/fdroid/fdroid/installer/InstallIntoSystemDialogActivity.java rename to F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java index 8fe2b102c..c5680e5be 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/InstallIntoSystemDialogActivity.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java @@ -17,7 +17,7 @@ * MA 02110-1301, USA. */ -package org.fdroid.fdroid.installer; +package org.fdroid.fdroid.privileged.install; import android.app.Activity; import android.app.Notification; @@ -40,13 +40,14 @@ import org.fdroid.fdroid.FDroid; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; +import org.fdroid.fdroid.installer.Installer; import eu.chainfire.libsuperuser.Shell; /** * Note: This activity has no view on its own, it displays consecutive dialogs. */ -public class InstallIntoSystemDialogActivity extends FragmentActivity { +public class InstallPrivilegedDialogActivity extends FragmentActivity { private static final String TAG = "InstallIntoSystem"; @@ -112,8 +113,8 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { if (false && probablyRoot) { // looks like we have root, at least su has a version number and is present - Intent installIntent = new Intent(context, InstallIntoSystemDialogActivity.class); - installIntent.setAction(InstallIntoSystemDialogActivity.ACTION_FIRST_TIME); + Intent installIntent = new Intent(context, InstallPrivilegedDialogActivity.class); + installIntent.setAction(InstallPrivilegedDialogActivity.ACTION_FIRST_TIME); installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent resultPendingIntent = @@ -157,7 +158,7 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId()); - String message = getString(R.string.system_install_first_time_message) + "

" + InstallIntoSystem.create(getApplicationContext()).getWarningInfo(); + String message = getString(R.string.system_install_first_time_message) + "

" + InstallPrivileged.create(getApplicationContext()).getWarningInfo(); AlertDialog.Builder builder = new AlertDialog.Builder(theme) .setMessage(Html.fromHtml(message)) @@ -170,8 +171,8 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - InstallIntoSystemDialogActivity.this.setResult(Activity.RESULT_CANCELED); - InstallIntoSystemDialogActivity.this.finish(); + InstallPrivilegedDialogActivity.this.setResult(Activity.RESULT_CANCELED); + InstallPrivilegedDialogActivity.this.finish(); } }); builder.create().show(); @@ -188,7 +189,7 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { super.onPreExecute(); // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay - ContextThemeWrapper theme = new ContextThemeWrapper(InstallIntoSystemDialogActivity.this, + ContextThemeWrapper theme = new ContextThemeWrapper(InstallPrivilegedDialogActivity.this, FDroidApp.getCurThemeResId()); mProgressDialog = new ProgressDialog(theme); @@ -224,7 +225,7 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { if (!ACTION_FIRST_TIME.equals(action)) { // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay - ContextThemeWrapper theme = new ContextThemeWrapper(InstallIntoSystemDialogActivity.this, + ContextThemeWrapper theme = new ContextThemeWrapper(InstallPrivilegedDialogActivity.this, FDroidApp.getCurThemeResId()); AlertDialog.Builder alertBuilder = new AlertDialog.Builder(theme) @@ -233,8 +234,8 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { .setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - InstallIntoSystemDialogActivity.this.setResult(Activity.RESULT_CANCELED); - InstallIntoSystemDialogActivity.this.finish(); + InstallPrivilegedDialogActivity.this.setResult(Activity.RESULT_CANCELED); + InstallPrivilegedDialogActivity.this.finish(); } }); alertBuilder.create().show(); @@ -254,7 +255,7 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { super.onPreExecute(); // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay - ContextThemeWrapper theme = new ContextThemeWrapper(InstallIntoSystemDialogActivity.this, + ContextThemeWrapper theme = new ContextThemeWrapper(InstallPrivilegedDialogActivity.this, FDroidApp.getCurThemeResId()); mProgressDialog = new ProgressDialog(theme); @@ -266,7 +267,7 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { @Override protected Void doInBackground(Void... voids) { - InstallIntoSystem.create(getApplicationContext()).runInstall(); + InstallPrivileged.create(getApplicationContext()).runInstall(); return null; } }; @@ -289,9 +290,9 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - InstallIntoSystemDialogActivity.this.setResult(success ? Activity.RESULT_OK : Activity.RESULT_CANCELED); - InstallIntoSystemDialogActivity.this.finish(); - startActivity(new Intent(InstallIntoSystemDialogActivity.this, FDroid.class)); + InstallPrivilegedDialogActivity.this.setResult(success ? Activity.RESULT_OK : Activity.RESULT_CANCELED); + InstallPrivilegedDialogActivity.this.finish(); + startActivity(new Intent(InstallPrivilegedDialogActivity.this, FDroid.class)); } }) .setCancelable(false); @@ -317,8 +318,8 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - InstallIntoSystemDialogActivity.this.setResult(Activity.RESULT_CANCELED); - InstallIntoSystemDialogActivity.this.finish(); + InstallPrivilegedDialogActivity.this.setResult(Activity.RESULT_CANCELED); + InstallPrivilegedDialogActivity.this.finish(); } }); builder.create().show(); @@ -329,8 +330,8 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - InstallIntoSystemDialogActivity.this.setResult(Activity.RESULT_CANCELED); - InstallIntoSystemDialogActivity.this.finish(); + InstallPrivilegedDialogActivity.this.setResult(Activity.RESULT_CANCELED); + InstallPrivilegedDialogActivity.this.finish(); } }); builder.create().show(); @@ -345,7 +346,7 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { super.onPreExecute(); // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay - ContextThemeWrapper theme = new ContextThemeWrapper(InstallIntoSystemDialogActivity.this, + ContextThemeWrapper theme = new ContextThemeWrapper(InstallPrivilegedDialogActivity.this, FDroidApp.getCurThemeResId()); mProgressDialog = new ProgressDialog(theme); @@ -357,7 +358,7 @@ public class InstallIntoSystemDialogActivity extends FragmentActivity { @Override protected Void doInBackground(Void... voids) { - InstallIntoSystem.create(getApplicationContext()).runUninstall(); + InstallPrivileged.create(getApplicationContext()).runUninstall(); return null; } diff --git a/F-Droid/src/org/fdroid/fdroid/installer/AppDiff.java b/F-Droid/src/org/fdroid/fdroid/privileged/views/AppDiff.java similarity index 94% rename from F-Droid/src/org/fdroid/fdroid/installer/AppDiff.java rename to F-Droid/src/org/fdroid/fdroid/privileged/views/AppDiff.java index 2391cb096..95b94cc28 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/AppDiff.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/views/AppDiff.java @@ -16,7 +16,7 @@ ** limitations under the License. */ -package org.fdroid.fdroid.installer; +package org.fdroid.fdroid.privileged.views; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; @@ -25,10 +25,10 @@ import android.net.Uri; public class AppDiff { - final PackageManager mPm; - final PackageInfo mPkgInfo; + public final PackageManager mPm; + public final PackageInfo mPkgInfo; - ApplicationInfo mInstalledAppInfo = null; + public ApplicationInfo mInstalledAppInfo = null; public AppDiff(PackageManager mPm, Uri mPackageURI) { this.mPm = mPm; diff --git a/F-Droid/src/org/fdroid/fdroid/installer/AppSecurityPermissions.java b/F-Droid/src/org/fdroid/fdroid/privileged/views/AppSecurityPermissions.java similarity index 99% rename from F-Droid/src/org/fdroid/fdroid/installer/AppSecurityPermissions.java rename to F-Droid/src/org/fdroid/fdroid/privileged/views/AppSecurityPermissions.java index e65ef76cf..c6754b71c 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/AppSecurityPermissions.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/views/AppSecurityPermissions.java @@ -15,7 +15,7 @@ ** See the License for the specific language governing permissions and ** limitations under the License. */ -package org.fdroid.fdroid.installer; +package org.fdroid.fdroid.privileged.views; import android.annotation.TargetApi; import android.content.Context; diff --git a/F-Droid/src/org/fdroid/fdroid/installer/CaffeinatedScrollView.java b/F-Droid/src/org/fdroid/fdroid/privileged/views/CaffeinatedScrollView.java similarity index 98% rename from F-Droid/src/org/fdroid/fdroid/installer/CaffeinatedScrollView.java rename to F-Droid/src/org/fdroid/fdroid/privileged/views/CaffeinatedScrollView.java index 37b96b419..f43dbc053 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/CaffeinatedScrollView.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/views/CaffeinatedScrollView.java @@ -15,7 +15,7 @@ ** limitations under the License. */ -package org.fdroid.fdroid.installer; +package org.fdroid.fdroid.privileged.views; import android.content.Context; import android.graphics.Canvas; diff --git a/F-Droid/src/org/fdroid/fdroid/installer/InstallConfirmActivity.java b/F-Droid/src/org/fdroid/fdroid/privileged/views/InstallConfirmActivity.java similarity index 99% rename from F-Droid/src/org/fdroid/fdroid/installer/InstallConfirmActivity.java rename to F-Droid/src/org/fdroid/fdroid/privileged/views/InstallConfirmActivity.java index aeaf16e8b..dae78e90f 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/InstallConfirmActivity.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/views/InstallConfirmActivity.java @@ -16,7 +16,7 @@ ** limitations under the License. */ -package org.fdroid.fdroid.installer; +package org.fdroid.fdroid.privileged.views; import android.app.Activity; import android.content.Context; diff --git a/F-Droid/src/org/fdroid/fdroid/installer/TabsAdapter.java b/F-Droid/src/org/fdroid/fdroid/privileged/views/TabsAdapter.java similarity index 99% rename from F-Droid/src/org/fdroid/fdroid/installer/TabsAdapter.java rename to F-Droid/src/org/fdroid/fdroid/privileged/views/TabsAdapter.java index eef50eb1b..02372fd84 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/TabsAdapter.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/views/TabsAdapter.java @@ -14,7 +14,7 @@ ** See the License for the specific language governing permissions and ** limitations under the License. */ -package org.fdroid.fdroid.installer; +package org.fdroid.fdroid.privileged.views; import android.app.Activity; import android.content.Context; diff --git a/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java b/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java index 4b111c0d4..40804dd88 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java +++ b/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java @@ -19,7 +19,7 @@ import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.PreferencesActivity; import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; -import org.fdroid.fdroid.installer.InstallIntoSystemDialogActivity; +import org.fdroid.fdroid.privileged.install.InstallPrivilegedDialogActivity; import org.fdroid.fdroid.installer.Installer; import java.util.Locale; @@ -221,8 +221,8 @@ public class PreferencesFragment extends PreferenceFragment alertBuilder.setPositiveButton(R.string.system_permission_install_via_root, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - Intent installIntent = new Intent(getActivity(), InstallIntoSystemDialogActivity.class); - installIntent.setAction(InstallIntoSystemDialogActivity.ACTION_INSTALL); + Intent installIntent = new Intent(getActivity(), InstallPrivilegedDialogActivity.class); + installIntent.setAction(InstallPrivilegedDialogActivity.ACTION_INSTALL); startActivity(installIntent); } }); @@ -249,8 +249,8 @@ public class PreferencesFragment extends PreferenceFragment @Override public boolean onPreferenceClick(Preference preference) { - Intent uninstallIntent = new Intent(getActivity(), InstallIntoSystemDialogActivity.class); - uninstallIntent.setAction(InstallIntoSystemDialogActivity.ACTION_UNINSTALL); + Intent uninstallIntent = new Intent(getActivity(), InstallPrivilegedDialogActivity.class); + uninstallIntent.setAction(InstallPrivilegedDialogActivity.ACTION_UNINSTALL); startActivity(uninstallIntent); return true; From e87693d989df0d9a809accd8305f9bbc80995e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 26 Aug 2015 20:39:08 +0200 Subject: [PATCH 02/10] Add Privileged F-Droid project --- .../privileged/IPrivilegedCallback.aidl | 26 ++ .../fdroid/privileged/IPrivilegedService.aidl | 65 ++++ Privileged-F-Droid/.gitignore | 33 ++ Privileged-F-Droid/build.gradle | 51 +++ .../src/main/AndroidManifest.xml | 33 ++ .../privileged/IPrivilegedCallback.aidl | 26 ++ .../fdroid/privileged/IPrivilegedService.aidl | 65 ++++ .../content/pm/IPackageDeleteObserver.java | 54 ++++ .../content/pm/IPackageInstallObserver.java | 54 ++++ .../fdroid/privileged/PrivilegedService.java | 305 ++++++++++++++++++ .../main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 4548 bytes .../main/res/drawable-ldpi/ic_launcher.png | Bin 0 -> 1986 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 2664 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 6033 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 10295 bytes .../main/res/drawable-xxxhdpi/ic_launcher.png | Bin 0 -> 14497 bytes .../src/main/res/values/strings.xml | 6 + 17 files changed, 718 insertions(+) create mode 100644 F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl create mode 100644 F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedService.aidl create mode 100644 Privileged-F-Droid/.gitignore create mode 100644 Privileged-F-Droid/build.gradle create mode 100644 Privileged-F-Droid/src/main/AndroidManifest.xml create mode 100644 Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl create mode 100644 Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl create mode 100644 Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java create mode 100644 Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java create mode 100644 Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java create mode 100644 Privileged-F-Droid/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/drawable-ldpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/drawable-xxxhdpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/values/strings.xml diff --git a/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl b/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl new file mode 100644 index 000000000..fc476fafe --- /dev/null +++ b/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +interface IPrivilegedCallback { + + void handleResult(in String packageName, in int returnCode); + +} \ No newline at end of file diff --git a/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedService.aidl b/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedService.aidl new file mode 100644 index 000000000..b5b74ff4b --- /dev/null +++ b/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedService.aidl @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +import org.fdroid.fdroid.privileged.IPrivilegedCallback; + +/** + * Asynchronous (oneway) IPC calls! + */ +oneway interface IPrivilegedService { + + /** + * Docs based on PackageManager.installPackage() + * + * Install a package. Since this may take a little while, the result will + * be posted back to the given callback. An installation will fail if the + * package named in the package file's manifest is already installed, or if there's no space + * available on the device. + * + * @param packageURI The location of the package file to install. This can be a 'file:' or a + * 'content:' URI. + * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * @param installerPackageName Optional package name of the application that is performing the + * installation. This identifies which market the package came from. + * @param callback An callback to get notified when the package installation is + * complete. + */ + void installPackage(in Uri packageURI, in int flags, in String installerPackageName, + in IPrivilegedCallback callback); + + + /** + * Docs based on PackageManager.deletePackage() + * + * Attempts to delete a package. Since this may take a little while, the result will + * be posted back to the given observer. A deletion will fail if the + * named package cannot be found, or if the named package is a "system package". + * + * @param packageName The name of the package to delete + * @param flags - possible values: {@link #DELETE_KEEP_DATA}, + * {@link #DELETE_ALL_USERS}. + * @param callback An callback to get notified when the package deletion is + * complete. + */ + void deletePackage(in String packageName, in int flags, in IPrivilegedCallback callback); + +} \ No newline at end of file diff --git a/Privileged-F-Droid/.gitignore b/Privileged-F-Droid/.gitignore new file mode 100644 index 000000000..a44cc0f0f --- /dev/null +++ b/Privileged-F-Droid/.gitignore @@ -0,0 +1,33 @@ +#Android specific +bin +gen +obj +lint.xml +local.properties +release.properties +ant.properties +*.class +*.apk + +#Gradle +.gradle +build +gradle.properties + +#Maven +target +pom.xml.* + +#Eclipse +.project +.classpath +.settings +.metadata + +#IntelliJ IDEA +.idea +*.iml + +#Lint output +lint-report.html +lint-report_files/* \ No newline at end of file diff --git a/Privileged-F-Droid/build.gradle b/Privileged-F-Droid/build.gradle new file mode 100644 index 000000000..5545f4366 --- /dev/null +++ b/Privileged-F-Droid/build.gradle @@ -0,0 +1,51 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion '23.0.0' + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + + compileOptions { + compileOptions.encoding = "UTF-8" + + // Use Java 1.7, requires minSdk 8 + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + buildTypes { + release { + minifyEnabled true + + // Reference them in the java files with e.g. BuildConfig.F_DROID_CERT_SHA512. + buildConfigField "String", "F_DROID_CERT_SHA512", "\"9ba5d51a0d5c3627e270c2542b761937c721b0d8a1caed88bd3b2f21add138c2f16e295ce67bef21b21e0b75d5a0c6fd13d67efeb85c198cffa365755c94f4c2\"" + } + + debug { + + // Reference them in the java files with e.g. BuildConfig.F_DROID_CERT_SHA512. + buildConfigField "String", "F_DROID_CERT_SHA512", "\"9ba5d51a0d5c3627e270c2542b761937c721b0d8a1caed88bd3b2f21add138c2f16e295ce67bef21b21e0b75d5a0c6fd13d67efeb85c198cffa365755c94f4c2\"" + } + } + + lintOptions { + // Do not abort build if lint finds errors + abortOnError false + } + +} diff --git a/Privileged-F-Droid/src/main/AndroidManifest.xml b/Privileged-F-Droid/src/main/AndroidManifest.xml new file mode 100644 index 000000000..63bf561ed --- /dev/null +++ b/Privileged-F-Droid/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl b/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl new file mode 100644 index 000000000..fc476fafe --- /dev/null +++ b/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +interface IPrivilegedCallback { + + void handleResult(in String packageName, in int returnCode); + +} \ No newline at end of file diff --git a/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl b/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl new file mode 100644 index 000000000..b5b74ff4b --- /dev/null +++ b/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +import org.fdroid.fdroid.privileged.IPrivilegedCallback; + +/** + * Asynchronous (oneway) IPC calls! + */ +oneway interface IPrivilegedService { + + /** + * Docs based on PackageManager.installPackage() + * + * Install a package. Since this may take a little while, the result will + * be posted back to the given callback. An installation will fail if the + * package named in the package file's manifest is already installed, or if there's no space + * available on the device. + * + * @param packageURI The location of the package file to install. This can be a 'file:' or a + * 'content:' URI. + * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * @param installerPackageName Optional package name of the application that is performing the + * installation. This identifies which market the package came from. + * @param callback An callback to get notified when the package installation is + * complete. + */ + void installPackage(in Uri packageURI, in int flags, in String installerPackageName, + in IPrivilegedCallback callback); + + + /** + * Docs based on PackageManager.deletePackage() + * + * Attempts to delete a package. Since this may take a little while, the result will + * be posted back to the given observer. A deletion will fail if the + * named package cannot be found, or if the named package is a "system package". + * + * @param packageName The name of the package to delete + * @param flags - possible values: {@link #DELETE_KEEP_DATA}, + * {@link #DELETE_ALL_USERS}. + * @param callback An callback to get notified when the package deletion is + * complete. + */ + void deletePackage(in String packageName, in int flags, in IPrivilegedCallback callback); + +} \ No newline at end of file diff --git a/Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java b/Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java new file mode 100644 index 000000000..be0d4de81 --- /dev/null +++ b/Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package android.content.pm; + +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; + +/** + * Just a non-working implementation of this Stub to satisfy compiler! + */ +public interface IPackageDeleteObserver extends IInterface { + + abstract class Stub extends Binder implements android.content.pm.IPackageDeleteObserver { + + public Stub() { + throw new RuntimeException("Stub!"); + } + + public static IPackageDeleteObserver asInterface(IBinder obj) { + throw new RuntimeException("Stub!"); + } + + public IBinder asBinder() { + throw new RuntimeException("Stub!"); + } + + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + throw new RuntimeException("Stub!"); + } + } + + void packageDeleted(java.lang.String packageName, int returnCode) throws RemoteException; +} diff --git a/Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java b/Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java new file mode 100644 index 000000000..ae5b3ab12 --- /dev/null +++ b/Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package android.content.pm; + +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; + +/** + * Just a non-working implementation of this Stub to satisfy compiler! + */ +public interface IPackageInstallObserver extends IInterface { + + abstract class Stub extends Binder implements android.content.pm.IPackageInstallObserver { + + public Stub() { + throw new RuntimeException("Stub!"); + } + + public static android.content.pm.IPackageInstallObserver asInterface(IBinder obj) { + throw new RuntimeException("Stub!"); + } + + public IBinder asBinder() { + throw new RuntimeException("Stub!"); + } + + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + throw new RuntimeException("Stub!"); + } + } + + void packageInstalled(String packageName, int returnCode) throws RemoteException; +} \ No newline at end of file diff --git a/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java b/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java new file mode 100644 index 000000000..b727e7408 --- /dev/null +++ b/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +import android.annotation.SuppressLint; +import android.app.Service; +import android.content.Intent; +import android.content.pm.IPackageDeleteObserver; +import android.content.pm.IPackageInstallObserver; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.net.Uri; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * This service provides an API via AIDL IPC for the main F-Droid app to install/delete packages. + *

+ * Security: + * Binding only works when,... + * - packageName is "org.fdroid.fdroid" + * - signature is equal or BuildConfig.DEBUG + */ +public class PrivilegedService extends Service { + + public static final String TAG = "PrivilegedFDroid"; + + private static final String F_DROID_PACKAGE = "org.fdroid.fdroid"; + + private Method mInstallMethod; + private Method mDeleteMethod; + + private void installPackageImpl(Uri packageURI, int flags, String installerPackageName, + final IPrivilegedCallback callback) { + + // Internal callback from the system + IPackageInstallObserver.Stub installObserver = new IPackageInstallObserver.Stub() { + @Override + public void packageInstalled(String packageName, int returnCode) throws RemoteException { + // forward this internal callback to our callback + try { + callback.handleResult(packageName, returnCode); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + }; + + // execute internal method + try { + mInstallMethod.invoke(getPackageManager(), packageURI, installObserver, + flags, installerPackageName); + } catch (Exception e) { + Log.e(TAG, "Android not compatible!", e); + try { + callback.handleResult(null, 0); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + } + + private void deletePackageImpl(String packageName, int flags, final IPrivilegedCallback callback) { + + // Internal callback from the system + IPackageDeleteObserver.Stub deleteObserver = new IPackageDeleteObserver.Stub() { + @Override + public void packageDeleted(String packageName, int returnCode) throws RemoteException { + // forward this internal callback to our callback + try { + callback.handleResult(packageName, returnCode); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + }; + + // execute internal method + try { + mDeleteMethod.invoke(getPackageManager(), packageName, deleteObserver, flags); + } catch (Exception e) { + Log.e(TAG, "Android not compatible!", e); + try { + callback.handleResult(null, 0); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + + } + + private final IPrivilegedService.Stub mBinder = new IPrivilegedService.Stub() { + @Override + public void installPackage(Uri packageURI, int flags, String installerPackageName, + IPrivilegedCallback callback) { + if (isAllowed()) { + installPackageImpl(packageURI, flags, installerPackageName, callback); + } + } + + @Override + public void deletePackage(String packageName, int flags, IPrivilegedCallback callback) { + if (isAllowed()) { + deletePackageImpl(packageName, flags, callback); + } + } + }; + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + private boolean isAllowed() { + // Check that binding app is allowed to use this API + try { + + barrierPackageName(); + barrierPackageCertificate(); + + } catch (WrongPackageCertificateException e) { + Log.e(TAG, "package certificate is not allowed!", e); + return false; + } catch (WrongPackageNameException e) { + Log.e(TAG, "package name is not allowed!", e); + return false; + } + + return true; + } + + /** + * Checks if process that binds to this service (i.e. the package name corresponding to the + * process) is allowed. Only returns when package name is allowed! + * + * @throws WrongPackageNameException + */ + private void barrierPackageName() throws WrongPackageNameException { + int uid = Binder.getCallingUid(); + String[] callingPackages = getPackageManager().getPackagesForUid(uid); + + // is calling package allowed to use this service? + for (String currentPkg : callingPackages) { + if (F_DROID_PACKAGE.equals(currentPkg)) { + return; + } + } + + throw new WrongPackageNameException("package name is not allowed"); + } + + private void barrierPackageCertificate() throws WrongPackageCertificateException { + String packageName = getCurrentCallingPackage(); + + byte[] packageCertificate; + try { + packageCertificate = getPackageCertificate(packageName); + } catch (PackageManager.NameNotFoundException e) { + throw new WrongPackageCertificateException(e.getMessage()); + } + + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-512"); + } catch (NoSuchAlgorithmException e) { + throw new WrongPackageCertificateException("SHA-512 not available!"); + } + byte[] hash = md.digest(packageCertificate); + + Log.d(TAG, "hash:" + getHex(hash)); + Log.d(TAG, "F_DROID_CERT_SHA512:" + BuildConfig.F_DROID_CERT_SHA512); + + if (getHex(hash).equals(BuildConfig.F_DROID_CERT_SHA512) + || BuildConfig.DEBUG) { + return; + } + + throw new WrongPackageCertificateException("certificate not allowed!"); + } + + private byte[] getPackageCertificate(String packageName) throws PackageManager.NameNotFoundException { + // we do check the byte array of *all* signatures + @SuppressLint("PackageManagerGetSignatures") + PackageInfo pkgInfo = getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + + // NOTE: Silly Android API naming: Signatures are actually certificates + Signature[] certificates = pkgInfo.signatures; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + for (Signature cert : certificates) { + try { + outputStream.write(cert.toByteArray()); + } catch (IOException e) { + throw new RuntimeException("Should not happen! Writing ByteArrayOutputStream to concat certificates failed"); + } + } + + // Even if an apk has several certificates, these certificates should never change + // Google Play does not allow the introduction of new certificates into an existing apk + // Also see this attack: http://stackoverflow.com/a/10567852 + return outputStream.toByteArray(); + } + + /** + * Returns package name associated with the UID, which is assigned to the process that sent you the + * current transaction that is being processed :) + * + * @return package name + */ + protected String getCurrentCallingPackage() { + String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); + + // NOTE: No support for sharedUserIds + // callingPackages contains more than one entry when sharedUserId has been used + // No plans to support sharedUserIds due to many bugs connected to them: + // http://java-hamster.blogspot.de/2010/05/androids-shareduserid.html + return callingPackages[0]; + } + + @Override + public void onCreate() { + super.onCreate(); + + // get internal methods via reflection + try { + Class[] installTypes = { + Uri.class, IPackageInstallObserver.class, int.class, + String.class + }; + Class[] deleteTypes = { + String.class, IPackageDeleteObserver.class, + int.class + }; + + PackageManager pm = getPackageManager(); + mInstallMethod = pm.getClass().getMethod("installPackage", installTypes); + mDeleteMethod = pm.getClass().getMethod("deletePackage", deleteTypes); + } catch (NoSuchMethodException e) { + Log.e(TAG, "Android not compatible!", e); + stopSelf(); + } + } + + private String getHex(byte[] byteData) { + StringBuilder hexString = new StringBuilder(); + for (byte aByteData : byteData) { + String hex = Integer.toHexString(0xff & aByteData); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + + return hexString.toString(); + } + + public static class WrongPackageCertificateException extends Exception { + private static final long serialVersionUID = -1294642703122196028L; + + public WrongPackageCertificateException(String message) { + super(message); + } + } + + public static class WrongPackageNameException extends Exception { + private static final long serialVersionUID = -2294642703111196028L; + + public WrongPackageNameException(String message) { + super(message); + } + } + + public static class AndroidNotCompatibleException extends Exception { + private static final long serialVersionUID = -3294642703111196028L; + + public AndroidNotCompatibleException(String message) { + super(message); + } + } +} diff --git a/Privileged-F-Droid/src/main/res/drawable-hdpi/ic_launcher.png b/Privileged-F-Droid/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..88138a47a6560ff25978dc35fb11cc0f85459952 GIT binary patch literal 4548 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 W!7{!k@hV3E0000bhm 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 WCEE79^Y#25Kwd^gx?0jK^nU=My12^# literal 0 HcmV?d00001 diff --git a/Privileged-F-Droid/src/main/res/drawable-xxxhdpi/ic_launcher.png b/Privileged-F-Droid/src/main/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c012986f5299366d0a00859626c75b4046c8b5c7 GIT binary patch literal 14497 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 + + + F-Droid Privileged + + From 73cedf858bfbeb093a5183041c5adf9b5f9f4833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 26 Aug 2015 21:37:32 +0200 Subject: [PATCH 03/10] Use protectionLevel signature for security --- .../src/main/AndroidManifest.xml | 10 +- .../fdroid/privileged/PrivilegedService.java | 164 +----------------- 2 files changed, 11 insertions(+), 163 deletions(-) diff --git a/Privileged-F-Droid/src/main/AndroidManifest.xml b/Privileged-F-Droid/src/main/AndroidManifest.xml index 63bf561ed..e919ee606 100644 --- a/Privileged-F-Droid/src/main/AndroidManifest.xml +++ b/Privileged-F-Droid/src/main/AndroidManifest.xml @@ -11,6 +11,14 @@ android:name="android.permission.DELETE_PACKAGES" tools:ignore="ProtectedPermissions" /> + + + + android:permission="org.fdroid.fdroid.privileged.USE_SERVICE"> diff --git a/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java b/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java index b727e7408..d717d4b8d 100644 --- a/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java +++ b/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java @@ -19,40 +19,25 @@ package org.fdroid.fdroid.privileged; -import android.annotation.SuppressLint; import android.app.Service; import android.content.Intent; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.Signature; import android.net.Uri; -import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.lang.reflect.Method; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; /** * This service provides an API via AIDL IPC for the main F-Droid app to install/delete packages. - *

- * Security: - * Binding only works when,... - * - packageName is "org.fdroid.fdroid" - * - signature is equal or BuildConfig.DEBUG */ public class PrivilegedService extends Service { public static final String TAG = "PrivilegedFDroid"; - private static final String F_DROID_PACKAGE = "org.fdroid.fdroid"; - private Method mInstallMethod; private Method mDeleteMethod; @@ -119,16 +104,12 @@ public class PrivilegedService extends Service { @Override public void installPackage(Uri packageURI, int flags, String installerPackageName, IPrivilegedCallback callback) { - if (isAllowed()) { - installPackageImpl(packageURI, flags, installerPackageName, callback); - } + installPackageImpl(packageURI, flags, installerPackageName, callback); } @Override public void deletePackage(String packageName, int flags, IPrivilegedCallback callback) { - if (isAllowed()) { - deletePackageImpl(packageName, flags, callback); - } + deletePackageImpl(packageName, flags, callback); } }; @@ -137,111 +118,6 @@ public class PrivilegedService extends Service { return mBinder; } - private boolean isAllowed() { - // Check that binding app is allowed to use this API - try { - - barrierPackageName(); - barrierPackageCertificate(); - - } catch (WrongPackageCertificateException e) { - Log.e(TAG, "package certificate is not allowed!", e); - return false; - } catch (WrongPackageNameException e) { - Log.e(TAG, "package name is not allowed!", e); - return false; - } - - return true; - } - - /** - * Checks if process that binds to this service (i.e. the package name corresponding to the - * process) is allowed. Only returns when package name is allowed! - * - * @throws WrongPackageNameException - */ - private void barrierPackageName() throws WrongPackageNameException { - int uid = Binder.getCallingUid(); - String[] callingPackages = getPackageManager().getPackagesForUid(uid); - - // is calling package allowed to use this service? - for (String currentPkg : callingPackages) { - if (F_DROID_PACKAGE.equals(currentPkg)) { - return; - } - } - - throw new WrongPackageNameException("package name is not allowed"); - } - - private void barrierPackageCertificate() throws WrongPackageCertificateException { - String packageName = getCurrentCallingPackage(); - - byte[] packageCertificate; - try { - packageCertificate = getPackageCertificate(packageName); - } catch (PackageManager.NameNotFoundException e) { - throw new WrongPackageCertificateException(e.getMessage()); - } - - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-512"); - } catch (NoSuchAlgorithmException e) { - throw new WrongPackageCertificateException("SHA-512 not available!"); - } - byte[] hash = md.digest(packageCertificate); - - Log.d(TAG, "hash:" + getHex(hash)); - Log.d(TAG, "F_DROID_CERT_SHA512:" + BuildConfig.F_DROID_CERT_SHA512); - - if (getHex(hash).equals(BuildConfig.F_DROID_CERT_SHA512) - || BuildConfig.DEBUG) { - return; - } - - throw new WrongPackageCertificateException("certificate not allowed!"); - } - - private byte[] getPackageCertificate(String packageName) throws PackageManager.NameNotFoundException { - // we do check the byte array of *all* signatures - @SuppressLint("PackageManagerGetSignatures") - PackageInfo pkgInfo = getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES); - - // NOTE: Silly Android API naming: Signatures are actually certificates - Signature[] certificates = pkgInfo.signatures; - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - for (Signature cert : certificates) { - try { - outputStream.write(cert.toByteArray()); - } catch (IOException e) { - throw new RuntimeException("Should not happen! Writing ByteArrayOutputStream to concat certificates failed"); - } - } - - // Even if an apk has several certificates, these certificates should never change - // Google Play does not allow the introduction of new certificates into an existing apk - // Also see this attack: http://stackoverflow.com/a/10567852 - return outputStream.toByteArray(); - } - - /** - * Returns package name associated with the UID, which is assigned to the process that sent you the - * current transaction that is being processed :) - * - * @return package name - */ - protected String getCurrentCallingPackage() { - String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); - - // NOTE: No support for sharedUserIds - // callingPackages contains more than one entry when sharedUserId has been used - // No plans to support sharedUserIds due to many bugs connected to them: - // http://java-hamster.blogspot.de/2010/05/androids-shareduserid.html - return callingPackages[0]; - } - @Override public void onCreate() { super.onCreate(); @@ -266,40 +142,4 @@ public class PrivilegedService extends Service { } } - private String getHex(byte[] byteData) { - StringBuilder hexString = new StringBuilder(); - for (byte aByteData : byteData) { - String hex = Integer.toHexString(0xff & aByteData); - if (hex.length() == 1) { - hexString.append('0'); - } - hexString.append(hex); - } - - return hexString.toString(); - } - - public static class WrongPackageCertificateException extends Exception { - private static final long serialVersionUID = -1294642703122196028L; - - public WrongPackageCertificateException(String message) { - super(message); - } - } - - public static class WrongPackageNameException extends Exception { - private static final long serialVersionUID = -2294642703111196028L; - - public WrongPackageNameException(String message) { - super(message); - } - } - - public static class AndroidNotCompatibleException extends Exception { - private static final long serialVersionUID = -3294642703111196028L; - - public AndroidNotCompatibleException(String message) { - super(message); - } - } } From 09cdb08fdb4a1c8f142c8131b6aaacd2dace57ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 26 Aug 2015 21:52:57 +0200 Subject: [PATCH 04/10] Cleanup, restructure --- F-Droid-Privileged/.gitignore | 33 ++++ F-Droid-Privileged/build.gradle | 36 +++++ .../src/main/AndroidManifest.xml | 41 +++++ .../privileged/IPrivilegedCallback.aidl | 26 ++++ .../fdroid/privileged/IPrivilegedService.aidl | 65 ++++++++ .../content/pm/IPackageDeleteObserver.java | 54 +++++++ .../content/pm/IPackageInstallObserver.java | 54 +++++++ .../fdroid/privileged/PrivilegedService.java | 145 ++++++++++++++++++ .../main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 4548 bytes .../main/res/drawable-ldpi/ic_launcher.png | Bin 0 -> 1986 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 2664 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 6033 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 10295 bytes .../main/res/drawable-xxxhdpi/ic_launcher.png | Bin 0 -> 14497 bytes .../src/main/res/values/strings.xml | 6 + 15 files changed, 460 insertions(+) create mode 100644 F-Droid-Privileged/.gitignore create mode 100644 F-Droid-Privileged/build.gradle create mode 100644 F-Droid-Privileged/src/main/AndroidManifest.xml create mode 100644 F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl create mode 100644 F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl create mode 100644 F-Droid-Privileged/src/main/java/android/content/pm/IPackageDeleteObserver.java create mode 100644 F-Droid-Privileged/src/main/java/android/content/pm/IPackageInstallObserver.java create mode 100644 F-Droid-Privileged/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java create mode 100644 F-Droid-Privileged/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/drawable-ldpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/drawable-xxxhdpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/values/strings.xml diff --git a/F-Droid-Privileged/.gitignore b/F-Droid-Privileged/.gitignore new file mode 100644 index 000000000..a44cc0f0f --- /dev/null +++ b/F-Droid-Privileged/.gitignore @@ -0,0 +1,33 @@ +#Android specific +bin +gen +obj +lint.xml +local.properties +release.properties +ant.properties +*.class +*.apk + +#Gradle +.gradle +build +gradle.properties + +#Maven +target +pom.xml.* + +#Eclipse +.project +.classpath +.settings +.metadata + +#IntelliJ IDEA +.idea +*.iml + +#Lint output +lint-report.html +lint-report_files/* \ No newline at end of file diff --git a/F-Droid-Privileged/build.gradle b/F-Droid-Privileged/build.gradle new file mode 100644 index 000000000..0ff807fdd --- /dev/null +++ b/F-Droid-Privileged/build.gradle @@ -0,0 +1,36 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion '23.0.0' + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + + compileOptions { + compileOptions.encoding = "UTF-8" + + // Use Java 1.7, requires minSdk 8 + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + lintOptions { + // Do not abort build if lint finds errors + abortOnError false + } + +} diff --git a/F-Droid-Privileged/src/main/AndroidManifest.xml b/F-Droid-Privileged/src/main/AndroidManifest.xml new file mode 100644 index 000000000..127de4e1c --- /dev/null +++ b/F-Droid-Privileged/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl b/F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl new file mode 100644 index 000000000..fc476fafe --- /dev/null +++ b/F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +interface IPrivilegedCallback { + + void handleResult(in String packageName, in int returnCode); + +} \ No newline at end of file diff --git a/F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl b/F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl new file mode 100644 index 000000000..b5b74ff4b --- /dev/null +++ b/F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +import org.fdroid.fdroid.privileged.IPrivilegedCallback; + +/** + * Asynchronous (oneway) IPC calls! + */ +oneway interface IPrivilegedService { + + /** + * Docs based on PackageManager.installPackage() + * + * Install a package. Since this may take a little while, the result will + * be posted back to the given callback. An installation will fail if the + * package named in the package file's manifest is already installed, or if there's no space + * available on the device. + * + * @param packageURI The location of the package file to install. This can be a 'file:' or a + * 'content:' URI. + * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * @param installerPackageName Optional package name of the application that is performing the + * installation. This identifies which market the package came from. + * @param callback An callback to get notified when the package installation is + * complete. + */ + void installPackage(in Uri packageURI, in int flags, in String installerPackageName, + in IPrivilegedCallback callback); + + + /** + * Docs based on PackageManager.deletePackage() + * + * Attempts to delete a package. Since this may take a little while, the result will + * be posted back to the given observer. A deletion will fail if the + * named package cannot be found, or if the named package is a "system package". + * + * @param packageName The name of the package to delete + * @param flags - possible values: {@link #DELETE_KEEP_DATA}, + * {@link #DELETE_ALL_USERS}. + * @param callback An callback to get notified when the package deletion is + * complete. + */ + void deletePackage(in String packageName, in int flags, in IPrivilegedCallback callback); + +} \ No newline at end of file diff --git a/F-Droid-Privileged/src/main/java/android/content/pm/IPackageDeleteObserver.java b/F-Droid-Privileged/src/main/java/android/content/pm/IPackageDeleteObserver.java new file mode 100644 index 000000000..be0d4de81 --- /dev/null +++ b/F-Droid-Privileged/src/main/java/android/content/pm/IPackageDeleteObserver.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package android.content.pm; + +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; + +/** + * Just a non-working implementation of this Stub to satisfy compiler! + */ +public interface IPackageDeleteObserver extends IInterface { + + abstract class Stub extends Binder implements android.content.pm.IPackageDeleteObserver { + + public Stub() { + throw new RuntimeException("Stub!"); + } + + public static IPackageDeleteObserver asInterface(IBinder obj) { + throw new RuntimeException("Stub!"); + } + + public IBinder asBinder() { + throw new RuntimeException("Stub!"); + } + + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + throw new RuntimeException("Stub!"); + } + } + + void packageDeleted(java.lang.String packageName, int returnCode) throws RemoteException; +} diff --git a/F-Droid-Privileged/src/main/java/android/content/pm/IPackageInstallObserver.java b/F-Droid-Privileged/src/main/java/android/content/pm/IPackageInstallObserver.java new file mode 100644 index 000000000..ae5b3ab12 --- /dev/null +++ b/F-Droid-Privileged/src/main/java/android/content/pm/IPackageInstallObserver.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package android.content.pm; + +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; + +/** + * Just a non-working implementation of this Stub to satisfy compiler! + */ +public interface IPackageInstallObserver extends IInterface { + + abstract class Stub extends Binder implements android.content.pm.IPackageInstallObserver { + + public Stub() { + throw new RuntimeException("Stub!"); + } + + public static android.content.pm.IPackageInstallObserver asInterface(IBinder obj) { + throw new RuntimeException("Stub!"); + } + + public IBinder asBinder() { + throw new RuntimeException("Stub!"); + } + + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + throw new RuntimeException("Stub!"); + } + } + + void packageInstalled(String packageName, int returnCode) throws RemoteException; +} \ No newline at end of file diff --git a/F-Droid-Privileged/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java b/F-Droid-Privileged/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java new file mode 100644 index 000000000..d717d4b8d --- /dev/null +++ b/F-Droid-Privileged/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +import android.app.Service; +import android.content.Intent; +import android.content.pm.IPackageDeleteObserver; +import android.content.pm.IPackageInstallObserver; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.lang.reflect.Method; + +/** + * This service provides an API via AIDL IPC for the main F-Droid app to install/delete packages. + */ +public class PrivilegedService extends Service { + + public static final String TAG = "PrivilegedFDroid"; + + private Method mInstallMethod; + private Method mDeleteMethod; + + private void installPackageImpl(Uri packageURI, int flags, String installerPackageName, + final IPrivilegedCallback callback) { + + // Internal callback from the system + IPackageInstallObserver.Stub installObserver = new IPackageInstallObserver.Stub() { + @Override + public void packageInstalled(String packageName, int returnCode) throws RemoteException { + // forward this internal callback to our callback + try { + callback.handleResult(packageName, returnCode); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + }; + + // execute internal method + try { + mInstallMethod.invoke(getPackageManager(), packageURI, installObserver, + flags, installerPackageName); + } catch (Exception e) { + Log.e(TAG, "Android not compatible!", e); + try { + callback.handleResult(null, 0); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + } + + private void deletePackageImpl(String packageName, int flags, final IPrivilegedCallback callback) { + + // Internal callback from the system + IPackageDeleteObserver.Stub deleteObserver = new IPackageDeleteObserver.Stub() { + @Override + public void packageDeleted(String packageName, int returnCode) throws RemoteException { + // forward this internal callback to our callback + try { + callback.handleResult(packageName, returnCode); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + }; + + // execute internal method + try { + mDeleteMethod.invoke(getPackageManager(), packageName, deleteObserver, flags); + } catch (Exception e) { + Log.e(TAG, "Android not compatible!", e); + try { + callback.handleResult(null, 0); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + + } + + private final IPrivilegedService.Stub mBinder = new IPrivilegedService.Stub() { + @Override + public void installPackage(Uri packageURI, int flags, String installerPackageName, + IPrivilegedCallback callback) { + installPackageImpl(packageURI, flags, installerPackageName, callback); + } + + @Override + public void deletePackage(String packageName, int flags, IPrivilegedCallback callback) { + deletePackageImpl(packageName, flags, callback); + } + }; + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + @Override + public void onCreate() { + super.onCreate(); + + // get internal methods via reflection + try { + Class[] installTypes = { + Uri.class, IPackageInstallObserver.class, int.class, + String.class + }; + Class[] deleteTypes = { + String.class, IPackageDeleteObserver.class, + int.class + }; + + PackageManager pm = getPackageManager(); + mInstallMethod = pm.getClass().getMethod("installPackage", installTypes); + mDeleteMethod = pm.getClass().getMethod("deletePackage", deleteTypes); + } catch (NoSuchMethodException e) { + Log.e(TAG, "Android not compatible!", e); + stopSelf(); + } + } + +} diff --git a/F-Droid-Privileged/src/main/res/drawable-hdpi/ic_launcher.png b/F-Droid-Privileged/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..88138a47a6560ff25978dc35fb11cc0f85459952 GIT binary patch literal 4548 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 W!7{!k@hV3E0000bhm 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 WCEE79^Y#25Kwd^gx?0jK^nU=My12^# literal 0 HcmV?d00001 diff --git a/F-Droid-Privileged/src/main/res/drawable-xxxhdpi/ic_launcher.png b/F-Droid-Privileged/src/main/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c012986f5299366d0a00859626c75b4046c8b5c7 GIT binary patch literal 14497 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 + + + F-Droid Privileged + + From 85c8e7035da79629404feb80636c08c2f5063a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 26 Aug 2015 22:12:16 +0200 Subject: [PATCH 05/10] Move shared AIDL files into lib, restructure, start of install/delete code --- F-Droid-Privileged/build.gradle | 13 +- F-Droid/AndroidManifest.xml | 6 +- F-Droid/build.gradle | 2 + .../fdroid/installer/PrivilegedInstaller.java | 200 ++++++++++-------- .../privileged/IPrivilegedCallback.aidl | 26 --- .../fdroid/privileged/IPrivilegedService.aidl | 65 ------ Privileged-F-Droid/.gitignore | 33 --- Privileged-F-Droid/build.gradle | 51 ----- .../src/main/AndroidManifest.xml | 41 ---- .../privileged/IPrivilegedCallback.aidl | 26 --- .../fdroid/privileged/IPrivilegedService.aidl | 65 ------ .../content/pm/IPackageDeleteObserver.java | 54 ----- .../content/pm/IPackageInstallObserver.java | 54 ----- .../fdroid/privileged/PrivilegedService.java | 145 ------------- .../main/res/drawable-hdpi/ic_launcher.png | Bin 4548 -> 0 bytes .../main/res/drawable-ldpi/ic_launcher.png | Bin 1986 -> 0 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 2664 -> 0 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 6033 -> 0 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 10295 -> 0 bytes .../main/res/drawable-xxxhdpi/ic_launcher.png | Bin 14497 -> 0 bytes .../src/main/res/values/strings.xml | 6 - privileged-api-lib/build.gradle | 18 ++ .../src/main/AndroidManifest.xml | 6 + .../privileged/IPrivilegedCallback.aidl | 0 .../fdroid/privileged/IPrivilegedService.aidl | 0 settings.gradle | 2 + 26 files changed, 140 insertions(+), 673 deletions(-) delete mode 100644 F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl delete mode 100644 F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedService.aidl delete mode 100644 Privileged-F-Droid/.gitignore delete mode 100644 Privileged-F-Droid/build.gradle delete mode 100644 Privileged-F-Droid/src/main/AndroidManifest.xml delete mode 100644 Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl delete mode 100644 Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl delete mode 100644 Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java delete mode 100644 Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java delete mode 100644 Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java delete mode 100644 Privileged-F-Droid/src/main/res/drawable-hdpi/ic_launcher.png delete mode 100644 Privileged-F-Droid/src/main/res/drawable-ldpi/ic_launcher.png delete mode 100644 Privileged-F-Droid/src/main/res/drawable-mdpi/ic_launcher.png delete mode 100644 Privileged-F-Droid/src/main/res/drawable-xhdpi/ic_launcher.png delete mode 100644 Privileged-F-Droid/src/main/res/drawable-xxhdpi/ic_launcher.png delete mode 100644 Privileged-F-Droid/src/main/res/drawable-xxxhdpi/ic_launcher.png delete mode 100644 Privileged-F-Droid/src/main/res/values/strings.xml create mode 100644 privileged-api-lib/build.gradle create mode 100644 privileged-api-lib/src/main/AndroidManifest.xml rename {F-Droid-Privileged => privileged-api-lib}/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl (100%) rename {F-Droid-Privileged => privileged-api-lib}/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl (100%) diff --git a/F-Droid-Privileged/build.gradle b/F-Droid-Privileged/build.gradle index 0ff807fdd..69289d7dc 100644 --- a/F-Droid-Privileged/build.gradle +++ b/F-Droid-Privileged/build.gradle @@ -1,14 +1,9 @@ -buildscript { - repositories { - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:1.3.1' - } -} - apply plugin: 'com.android.application' +dependencies { + compile project(':privileged-api-lib') +} + android { compileSdkVersion 22 buildToolsVersion '23.0.0' diff --git a/F-Droid/AndroidManifest.xml b/F-Droid/AndroidManifest.xml index 60a124616..d703bb3ef 100644 --- a/F-Droid/AndroidManifest.xml +++ b/F-Droid/AndroidManifest.xml @@ -51,11 +51,7 @@ android:maxSdkVersion="18" /> - - - + - - - - - - - - - - - - - - - - - - diff --git a/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl b/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl deleted file mode 100644 index fc476fafe..000000000 --- a/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -package org.fdroid.fdroid.privileged; - -interface IPrivilegedCallback { - - void handleResult(in String packageName, in int returnCode); - -} \ No newline at end of file diff --git a/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl b/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl deleted file mode 100644 index b5b74ff4b..000000000 --- a/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -package org.fdroid.fdroid.privileged; - -import org.fdroid.fdroid.privileged.IPrivilegedCallback; - -/** - * Asynchronous (oneway) IPC calls! - */ -oneway interface IPrivilegedService { - - /** - * Docs based on PackageManager.installPackage() - * - * Install a package. Since this may take a little while, the result will - * be posted back to the given callback. An installation will fail if the - * package named in the package file's manifest is already installed, or if there's no space - * available on the device. - * - * @param packageURI The location of the package file to install. This can be a 'file:' or a - * 'content:' URI. - * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, - * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. - * @param installerPackageName Optional package name of the application that is performing the - * installation. This identifies which market the package came from. - * @param callback An callback to get notified when the package installation is - * complete. - */ - void installPackage(in Uri packageURI, in int flags, in String installerPackageName, - in IPrivilegedCallback callback); - - - /** - * Docs based on PackageManager.deletePackage() - * - * Attempts to delete a package. Since this may take a little while, the result will - * be posted back to the given observer. A deletion will fail if the - * named package cannot be found, or if the named package is a "system package". - * - * @param packageName The name of the package to delete - * @param flags - possible values: {@link #DELETE_KEEP_DATA}, - * {@link #DELETE_ALL_USERS}. - * @param callback An callback to get notified when the package deletion is - * complete. - */ - void deletePackage(in String packageName, in int flags, in IPrivilegedCallback callback); - -} \ No newline at end of file diff --git a/Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java b/Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java deleted file mode 100644 index be0d4de81..000000000 --- a/Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -package android.content.pm; - -import android.os.Binder; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Parcel; -import android.os.RemoteException; - -/** - * Just a non-working implementation of this Stub to satisfy compiler! - */ -public interface IPackageDeleteObserver extends IInterface { - - abstract class Stub extends Binder implements android.content.pm.IPackageDeleteObserver { - - public Stub() { - throw new RuntimeException("Stub!"); - } - - public static IPackageDeleteObserver asInterface(IBinder obj) { - throw new RuntimeException("Stub!"); - } - - public IBinder asBinder() { - throw new RuntimeException("Stub!"); - } - - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - throw new RuntimeException("Stub!"); - } - } - - void packageDeleted(java.lang.String packageName, int returnCode) throws RemoteException; -} diff --git a/Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java b/Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java deleted file mode 100644 index ae5b3ab12..000000000 --- a/Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -package android.content.pm; - -import android.os.Binder; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Parcel; -import android.os.RemoteException; - -/** - * Just a non-working implementation of this Stub to satisfy compiler! - */ -public interface IPackageInstallObserver extends IInterface { - - abstract class Stub extends Binder implements android.content.pm.IPackageInstallObserver { - - public Stub() { - throw new RuntimeException("Stub!"); - } - - public static android.content.pm.IPackageInstallObserver asInterface(IBinder obj) { - throw new RuntimeException("Stub!"); - } - - public IBinder asBinder() { - throw new RuntimeException("Stub!"); - } - - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - throw new RuntimeException("Stub!"); - } - } - - void packageInstalled(String packageName, int returnCode) throws RemoteException; -} \ No newline at end of file diff --git a/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java b/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java deleted file mode 100644 index d717d4b8d..000000000 --- a/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -package org.fdroid.fdroid.privileged; - -import android.app.Service; -import android.content.Intent; -import android.content.pm.IPackageDeleteObserver; -import android.content.pm.IPackageInstallObserver; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import java.lang.reflect.Method; - -/** - * This service provides an API via AIDL IPC for the main F-Droid app to install/delete packages. - */ -public class PrivilegedService extends Service { - - public static final String TAG = "PrivilegedFDroid"; - - private Method mInstallMethod; - private Method mDeleteMethod; - - private void installPackageImpl(Uri packageURI, int flags, String installerPackageName, - final IPrivilegedCallback callback) { - - // Internal callback from the system - IPackageInstallObserver.Stub installObserver = new IPackageInstallObserver.Stub() { - @Override - public void packageInstalled(String packageName, int returnCode) throws RemoteException { - // forward this internal callback to our callback - try { - callback.handleResult(packageName, returnCode); - } catch (RemoteException e1) { - Log.e(TAG, "RemoteException", e1); - } - } - }; - - // execute internal method - try { - mInstallMethod.invoke(getPackageManager(), packageURI, installObserver, - flags, installerPackageName); - } catch (Exception e) { - Log.e(TAG, "Android not compatible!", e); - try { - callback.handleResult(null, 0); - } catch (RemoteException e1) { - Log.e(TAG, "RemoteException", e1); - } - } - } - - private void deletePackageImpl(String packageName, int flags, final IPrivilegedCallback callback) { - - // Internal callback from the system - IPackageDeleteObserver.Stub deleteObserver = new IPackageDeleteObserver.Stub() { - @Override - public void packageDeleted(String packageName, int returnCode) throws RemoteException { - // forward this internal callback to our callback - try { - callback.handleResult(packageName, returnCode); - } catch (RemoteException e1) { - Log.e(TAG, "RemoteException", e1); - } - } - }; - - // execute internal method - try { - mDeleteMethod.invoke(getPackageManager(), packageName, deleteObserver, flags); - } catch (Exception e) { - Log.e(TAG, "Android not compatible!", e); - try { - callback.handleResult(null, 0); - } catch (RemoteException e1) { - Log.e(TAG, "RemoteException", e1); - } - } - - } - - private final IPrivilegedService.Stub mBinder = new IPrivilegedService.Stub() { - @Override - public void installPackage(Uri packageURI, int flags, String installerPackageName, - IPrivilegedCallback callback) { - installPackageImpl(packageURI, flags, installerPackageName, callback); - } - - @Override - public void deletePackage(String packageName, int flags, IPrivilegedCallback callback) { - deletePackageImpl(packageName, flags, callback); - } - }; - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - @Override - public void onCreate() { - super.onCreate(); - - // get internal methods via reflection - try { - Class[] installTypes = { - Uri.class, IPackageInstallObserver.class, int.class, - String.class - }; - Class[] deleteTypes = { - String.class, IPackageDeleteObserver.class, - int.class - }; - - PackageManager pm = getPackageManager(); - mInstallMethod = pm.getClass().getMethod("installPackage", installTypes); - mDeleteMethod = pm.getClass().getMethod("deletePackage", deleteTypes); - } catch (NoSuchMethodException e) { - Log.e(TAG, "Android not compatible!", e); - stopSelf(); - } - } - -} diff --git a/Privileged-F-Droid/src/main/res/drawable-hdpi/ic_launcher.png b/Privileged-F-Droid/src/main/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index 88138a47a6560ff25978dc35fb11cc0f85459952..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4548 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 W!7{!k@hV3E0000bhm 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 WCEE79^Y#25Kwd^gx?0jK^nU=My12^# diff --git a/Privileged-F-Droid/src/main/res/drawable-xxxhdpi/ic_launcher.png b/Privileged-F-Droid/src/main/res/drawable-xxxhdpi/ic_launcher.png deleted file mode 100644 index c012986f5299366d0a00859626c75b4046c8b5c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14497 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 - - - F-Droid Privileged - - diff --git a/privileged-api-lib/build.gradle b/privileged-api-lib/build.gradle new file mode 100644 index 000000000..392379301 --- /dev/null +++ b/privileged-api-lib/build.gradle @@ -0,0 +1,18 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 22 + buildToolsVersion '23.0.0' + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + + // Do not abort build if lint finds errors + lintOptions { + abortOnError false + } +} \ No newline at end of file diff --git a/privileged-api-lib/src/main/AndroidManifest.xml b/privileged-api-lib/src/main/AndroidManifest.xml new file mode 100644 index 000000000..d1978ceea --- /dev/null +++ b/privileged-api-lib/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl b/privileged-api-lib/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl similarity index 100% rename from F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl rename to privileged-api-lib/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl diff --git a/F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl b/privileged-api-lib/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl similarity index 100% rename from F-Droid-Privileged/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl rename to privileged-api-lib/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl diff --git a/settings.gradle b/settings.gradle index 263753759..b78f89eed 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,6 @@ include ':F-Droid' +include ':F-Droid-Privileged' +include ':privileged-api-lib' if ( hasProperty( 'sourceDeps' ) ) { include ':extern:AndroidPinning' From 976d06ea1aee603e254a0592903716a77d8aa224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 26 Aug 2015 22:27:31 +0200 Subject: [PATCH 06/10] Method to check for privleged permissions via IPC --- .../fdroid/privileged/PrivilegedService.java | 19 +++++++++++++++++++ .../fdroid/privileged/IPrivilegedService.aidl | 17 +++++++++-------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/F-Droid-Privileged/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java b/F-Droid-Privileged/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java index d717d4b8d..ae5d95e53 100644 --- a/F-Droid-Privileged/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java +++ b/F-Droid-Privileged/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java @@ -19,7 +19,10 @@ package org.fdroid.fdroid.privileged; +import android.*; +import android.Manifest; import android.app.Service; +import android.content.Context; import android.content.Intent; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; @@ -41,6 +44,17 @@ public class PrivilegedService extends Service { private Method mInstallMethod; private Method mDeleteMethod; + private boolean hasPrivilegedPermissionsImpl() { + boolean hasInstallPermission = + (getPackageManager().checkPermission(Manifest.permission.INSTALL_PACKAGES, getPackageName()) + == PackageManager.PERMISSION_GRANTED); + boolean hasDeletePermission = + (getPackageManager().checkPermission(Manifest.permission.DELETE_PACKAGES, getPackageName()) + == PackageManager.PERMISSION_GRANTED); + + return (hasInstallPermission && hasDeletePermission); + } + private void installPackageImpl(Uri packageURI, int flags, String installerPackageName, final IPrivilegedCallback callback) { @@ -101,6 +115,11 @@ public class PrivilegedService extends Service { } private final IPrivilegedService.Stub mBinder = new IPrivilegedService.Stub() { + @Override + public boolean hasPrivilegedPermissions() { + return hasPrivilegedPermissionsImpl(); + } + @Override public void installPackage(Uri packageURI, int flags, String installerPackageName, IPrivilegedCallback callback) { diff --git a/privileged-api-lib/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl b/privileged-api-lib/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl index b5b74ff4b..5c1724b1d 100644 --- a/privileged-api-lib/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl +++ b/privileged-api-lib/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl @@ -21,13 +21,13 @@ package org.fdroid.fdroid.privileged; import org.fdroid.fdroid.privileged.IPrivilegedCallback; -/** - * Asynchronous (oneway) IPC calls! - */ -oneway interface IPrivilegedService { +interface IPrivilegedService { + + boolean hasPrivilegedPermissions(); /** - * Docs based on PackageManager.installPackage() + * - Docs based on PackageManager.installPackage() + * - Asynchronous (oneway) IPC calls! * * Install a package. Since this may take a little while, the result will * be posted back to the given callback. An installation will fail if the @@ -43,12 +43,13 @@ oneway interface IPrivilegedService { * @param callback An callback to get notified when the package installation is * complete. */ - void installPackage(in Uri packageURI, in int flags, in String installerPackageName, + oneway void installPackage(in Uri packageURI, in int flags, in String installerPackageName, in IPrivilegedCallback callback); /** - * Docs based on PackageManager.deletePackage() + * - Docs based on PackageManager.deletePackage() + * - Asynchronous (oneway) IPC calls! * * Attempts to delete a package. Since this may take a little while, the result will * be posted back to the given observer. A deletion will fail if the @@ -60,6 +61,6 @@ oneway interface IPrivilegedService { * @param callback An callback to get notified when the package deletion is * complete. */ - void deletePackage(in String packageName, in int flags, in IPrivilegedCallback callback); + oneway void deletePackage(in String packageName, in int flags, in IPrivilegedCallback callback); } \ No newline at end of file From 57af421561116ac6e213e6bf3708f94533db4150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 27 Aug 2015 00:11:39 +0200 Subject: [PATCH 07/10] Check if PrivilegedInstaller is available, adapt InstallPrivileged --- F-Droid/res/values/strings.xml | 4 +- .../fdroid/fdroid/installer/Installer.java | 13 +---- .../fdroid/installer/PrivilegedInstaller.java | 48 +++++++++++++++++++ .../privileged/install/InstallPrivileged.java | 46 ++++++++++-------- .../InstallPrivilegedDialogActivity.java | 10 ++-- .../views/fragments/PreferencesFragment.java | 3 +- 6 files changed, 84 insertions(+), 40 deletions(-) diff --git a/F-Droid/res/values/strings.xml b/F-Droid/res/values/strings.xml index 737cbdc04..3c181aa36 100644 --- a/F-Droid/res/values/strings.xml +++ b/F-Droid/res/values/strings.xml @@ -308,8 +308,8 @@ The installation of F-Droid as a privileged app failed. The installation method is not supported by all Android distributions, please consult the F-Droid bug tracker for more information. installing… uninstalling… - Do you want to install F-Droid as a privileged app?\nThis takes up to 10 seconds where <b>no user interface</b> is shown. - Do you want to install F-Droid as a privileged app?\nThis takes up to 10 seconds where <b>no user interface</b> is shown and the device will be <b>rebooted</b> afterwards. + Do you want to install F-Droid as a privileged app?\nThis takes up to 10 seconds. + Do you want to install F-Droid as a privileged app?\nThis takes up to 10 seconds and the device will be <b>rebooted</b> afterwards. Looks like you have root access on your device. You can now install F-Droid as a privileged app, tightly coupled with the Android operating system. This allows F-Droid to install, upgrade and uninstall apps on its own. Do you want to uninstall F-Droid? This will uninstall F-Droid completely. diff --git a/F-Droid/src/org/fdroid/fdroid/installer/Installer.java b/F-Droid/src/org/fdroid/fdroid/installer/Installer.java index 7eb69a6d5..77f3f9143 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/Installer.java +++ b/F-Droid/src/org/fdroid/fdroid/installer/Installer.java @@ -109,7 +109,7 @@ abstract public class Installer { // system permissions and pref enabled -> SystemInstaller boolean isSystemInstallerEnabled = Preferences.get().isSystemInstallerEnabled(); if (isSystemInstallerEnabled) { - if (hasSystemPermissions(activity, pm)) { + if (PrivilegedInstaller.isAvailable(activity)) { Utils.DebugLog(TAG, "system permissions -> SystemInstaller"); try { @@ -147,17 +147,6 @@ abstract public class Installer { return null; } - public static boolean hasSystemPermissions(Context context, PackageManager pm) { - boolean hasInstallPermission = - (pm.checkPermission(permission.INSTALL_PACKAGES, context.getPackageName()) - == PackageManager.PERMISSION_GRANTED); - boolean hasDeletePermission = - (pm.checkPermission(permission.DELETE_PACKAGES, context.getPackageName()) - == PackageManager.PERMISSION_GRANTED); - - return (hasInstallPermission && hasDeletePermission); - } - public void installPackage(File apkFile) throws AndroidNotCompatibleException { // check if file exists... if (!apkFile.exists()) { diff --git a/F-Droid/src/org/fdroid/fdroid/installer/PrivilegedInstaller.java b/F-Droid/src/org/fdroid/fdroid/installer/PrivilegedInstaller.java index 1fa06dce8..23830c26b 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/PrivilegedInstaller.java +++ b/F-Droid/src/org/fdroid/fdroid/installer/PrivilegedInstaller.java @@ -29,6 +29,7 @@ import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.AlertDialog; @@ -84,7 +85,54 @@ public class PrivilegedInstaller extends Installer { InstallerCallback callback) throws AndroidNotCompatibleException { super(activity, pm, callback); this.mActivity = activity; + } + public static boolean isAvailable(Context context) { + + // check if installed + PackageManager pm = context.getPackageManager(); + try { + pm.getPackageInfo(PRIVILEGED_PACKAGE_NAME, PackageManager.GET_ACTIVITIES); + } catch (PackageManager.NameNotFoundException e) { + return false; + } + + // check if it has the privileged permissions granted + final Object mutex = new Object(); + final Bundle returnBundle = new Bundle(); + ServiceConnection mServiceConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + IPrivilegedService privService = IPrivilegedService.Stub.asInterface(service); + + try { + boolean hasPermissions = privService.hasPrivilegedPermissions(); + returnBundle.putBoolean("has_permissions", hasPermissions); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException", e); + } + + synchronized (mutex) { + mutex.notify(); + } + } + + public void onServiceDisconnected(ComponentName name) { + } + }; + Intent serviceIntent = new Intent(PRIVILEGED_INTENT); + serviceIntent.setPackage(PRIVILEGED_PACKAGE_NAME); + context.getApplicationContext().bindService(serviceIntent, mServiceConnection, + Context.BIND_AUTO_CREATE); + + synchronized (mutex) { + try { + mutex.wait(3000); + } catch (InterruptedException e) { + // don't care + } + } + + return (returnBundle.getBoolean("has_permission", false)); } @Override diff --git a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java index 0b7d13bd3..c69292f55 100644 --- a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java @@ -38,18 +38,22 @@ import eu.chainfire.libsuperuser.Shell; abstract class InstallPrivileged { protected final Context context; + protected final String apkPath; - public InstallPrivileged(final Context context) { + private static final String PACKAGE_NAME = "org.fdroid.fdroid.privileged"; + + public InstallPrivileged(final Context context, final String apkPath) { this.context = context; + this.apkPath = apkPath; } - public static InstallPrivileged create(final Context context) { + public static InstallPrivileged create(final Context context, final String apkPath) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return new LollipopImpl(context); + return new LollipopImpl(context, apkPath); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - return new KitKatToLollipopImpl(context); + return new KitKatToLollipopImpl(context, apkPath); } else { - return new PreKitKatImpl(context); + return new PreKitKatImpl(context, apkPath); } } @@ -65,10 +69,10 @@ abstract class InstallPrivileged { final void runUninstall() { final String[] commands = { - "am force-stop org.fdroid.fdroid", - "pm clear org.fdroid.fdroid", + "am force-stop " + PACKAGE_NAME, + "pm clear " + PACKAGE_NAME, "mount -o rw,remount /system", - "pm uninstall " + context.getPackageName(), + "pm uninstall " + PACKAGE_NAME, "rm -f " + getInstallPath(), "sleep 5", "mount -o ro,remount /system" @@ -82,26 +86,26 @@ abstract class InstallPrivileged { } protected String getInstallPath() { - return getSystemFolder() + "FDroid.apk"; + return getSystemFolder() + "FDroidPrivileged.apk"; } private List getInstallCommands() { final List commands = new ArrayList<>(); commands.add("mount -o rw,remount /system"); commands.addAll(getCopyToSystemCommands()); - commands.add("pm uninstall -k " + context.getPackageName()); // -k to retain data + commands.add("pm uninstall " + PACKAGE_NAME); commands.add("mv " + getInstallPath() + ".tmp " + getInstallPath()); commands.add("pm install -r " + getInstallPath()); commands.add("sleep 5"); // wait until the app is really installed commands.add("mount -o ro,remount /system"); - commands.add("am force-stop org.fdroid.fdroid"); + commands.add("am force-stop " + PACKAGE_NAME); commands.addAll(getPostInstallCommands()); return commands; } protected List getCopyToSystemCommands() { final List commands = new ArrayList<>(2); - commands.add("cat " + context.getPackageCodePath() + " > " + getInstallPath() + ".tmp"); + commands.add("cat " + apkPath + " > " + getInstallPath() + ".tmp"); commands.add("chmod 644 " + getInstallPath() + ".tmp"); return commands; } @@ -114,8 +118,8 @@ abstract class InstallPrivileged { private static class PreKitKatImpl extends InstallPrivileged { - public PreKitKatImpl(Context context) { - super(context); + public PreKitKatImpl(Context context, String apkPath) { + super(context, apkPath); } @Override @@ -127,8 +131,8 @@ abstract class InstallPrivileged { private static class KitKatToLollipopImpl extends InstallPrivileged { - public KitKatToLollipopImpl(Context context) { - super(context); + public KitKatToLollipopImpl(Context context, String apkPath) { + super(context, apkPath); } /** @@ -148,8 +152,8 @@ abstract class InstallPrivileged { */ private static class LollipopImpl extends InstallPrivileged { - public LollipopImpl(Context context) { - super(context); + public LollipopImpl(Context context, String apkPath) { + super(context, apkPath); } @Override @@ -167,7 +171,7 @@ abstract class InstallPrivileged { */ @Override protected String getSystemFolder() { - return "/system/priv-app/FDroid/"; + return "/system/priv-app/FDroidPrivileged/"; } /** @@ -178,13 +182,13 @@ abstract class InstallPrivileged { List commands = new ArrayList<>(3); commands.add("mkdir -p " + getSystemFolder()); // create app directory if not existing commands.add("chmod 755 " + getSystemFolder()); - commands.add("cat " + context.getPackageCodePath() + " > " + getInstallPath() + ".tmp"); + commands.add("cat " + apkPath + " > " + getInstallPath() + ".tmp"); commands.add("chmod 644 " + getInstallPath() + ".tmp"); return commands; } /** - * TODO: Currently only works with reboot + * NOTE: Only works with reboot *

* File observers on /system/priv-app/ have been removed because they don't work with the new * cluser-style layout. See diff --git a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java index c5680e5be..b413cad0b 100644 --- a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java @@ -41,6 +41,7 @@ import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; import org.fdroid.fdroid.installer.Installer; +import org.fdroid.fdroid.installer.PrivilegedInstaller; import eu.chainfire.libsuperuser.Shell; @@ -86,7 +87,7 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { if (Preferences.get().isFirstTime()) { Preferences.get().setFirstTime(false); - if (Installer.hasSystemPermissions(context, context.getPackageManager())) { + if (PrivilegedInstaller.isAvailable(context)) { Preferences.get().setSystemInstallerEnabled(true); } else { runFirstTime(context); @@ -158,7 +159,8 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId()); - String message = getString(R.string.system_install_first_time_message) + "

" + InstallPrivileged.create(getApplicationContext()).getWarningInfo(); + String message = getString(R.string.system_install_first_time_message) + "

" + + InstallPrivileged.create(getApplicationContext(), null).getWarningInfo(); AlertDialog.Builder builder = new AlertDialog.Builder(theme) .setMessage(Html.fromHtml(message)) @@ -279,7 +281,7 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId()); - final boolean success = Installer.hasSystemPermissions(this, this.getPackageManager()); + final boolean success = PrivilegedInstaller.isAvailable(this); // enable system installer on installation success Preferences.get().setSystemInstallerEnabled(success); @@ -303,7 +305,7 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId()); - final boolean systemApp = Installer.hasSystemPermissions(this, this.getPackageManager()); + final boolean systemApp = PrivilegedInstaller.isAvailable(this); if (systemApp) { AlertDialog.Builder builder = new AlertDialog.Builder(theme) diff --git a/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java b/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java index 40804dd88..f87644e75 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java +++ b/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java @@ -19,6 +19,7 @@ import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.PreferencesActivity; import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; +import org.fdroid.fdroid.installer.PrivilegedInstaller; import org.fdroid.fdroid.privileged.install.InstallPrivilegedDialogActivity; import org.fdroid.fdroid.installer.Installer; @@ -195,7 +196,7 @@ public class PreferencesFragment extends PreferenceFragment final CheckBoxPreference pref = (CheckBoxPreference) preference; if (pref.isChecked()) { - if (Installer.hasSystemPermissions(getActivity(), getActivity().getPackageManager())) { + if (PrivilegedInstaller.isAvailable(getActivity())) { // system-permission are granted, i.e. F-Droid is a system-app SharedPreferences.Editor editor = pref.getSharedPreferences().edit(); editor.putBoolean(Preferences.PREF_SYSTEM_INSTALLER, true); From 5bfc30651af270e18433ed8bc823ba6c776a35f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 27 Aug 2015 00:24:02 +0200 Subject: [PATCH 08/10] Refactor, allow installPrivileged from apk path --- F-Droid/res/values/strings.xml | 2 +- F-Droid/res/xml/preferences.xml | 4 +- .../src/org/fdroid/fdroid/Preferences.java | 26 ++++++------- .../fdroid/fdroid/installer/Installer.java | 3 +- .../privileged/install/InstallPrivileged.java | 38 +++++++++---------- .../InstallPrivilegedBootReceiver.java | 4 +- .../InstallPrivilegedDialogActivity.java | 9 ++--- .../views/fragments/PreferencesFragment.java | 23 ++++++----- 8 files changed, 52 insertions(+), 57 deletions(-) diff --git a/F-Droid/res/values/strings.xml b/F-Droid/res/values/strings.xml index 3c181aa36..8c262df2a 100644 --- a/F-Droid/res/values/strings.xml +++ b/F-Droid/res/values/strings.xml @@ -28,7 +28,7 @@ Enable privileged F-Droid Use privileged permissions to install, update, and remove packages Uninstall privileged F-Droid - Uninstall F-Droid when installed as a privileged app + Uninstalls the additional privileged F-Droid app Name of your Local Repo The advertised title of your local repo: %s Use Private Connection diff --git a/F-Droid/res/xml/preferences.xml b/F-Droid/res/xml/preferences.xml index 708ed5150..e038d5963 100644 --- a/F-Droid/res/xml/preferences.xml +++ b/F-Droid/res/xml/preferences.xml @@ -75,11 +75,11 @@ android:key="expert" /> diff --git a/F-Droid/src/org/fdroid/fdroid/Preferences.java b/F-Droid/src/org/fdroid/fdroid/Preferences.java index 1dd04f0a3..2b004d13c 100644 --- a/F-Droid/src/org/fdroid/fdroid/Preferences.java +++ b/F-Droid/src/org/fdroid/fdroid/Preferences.java @@ -49,8 +49,8 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi public static final String PREF_CACHE_APK = "cacheDownloaded"; public static final String PREF_EXPERT = "expert"; public static final String PREF_UPD_LAST = "lastUpdateCheck"; - public static final String PREF_SYSTEM_INSTALLER = "systemInstaller"; - public static final String PREF_UNINSTALL_SYSTEM_APP = "uninstallSystemApp"; + public static final String PREF_PRIVILEGED_INSTALLER = "privilegedInstaller"; + public static final String PREF_UNINSTALL_PRIVILEGED_APP = "uninstallPrivilegedApp"; public static final String PREF_LOCAL_REPO_NAME = "localRepoName"; public static final String PREF_LOCAL_REPO_HTTPS = "localRepoHttps"; public static final String PREF_LANGUAGE = "language"; @@ -59,12 +59,12 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi public static final String PREF_PROXY_PORT = "proxyPort"; public static final String PREF_SHOW_NFC_DURING_SWAP = "showNfcDuringSwap"; public static final String PREF_FIRST_TIME = "firstTime"; - public static final String PREF_POST_SYSTEM_INSTALL = "postSystemInstall"; + public static final String PREF_POST_PRIVILEGED_INSTALL = "postPrivilegedInstall"; private static final boolean DEFAULT_COMPACT_LAYOUT = false; private static final boolean DEFAULT_ROOTED = true; private static final int DEFAULT_UPD_HISTORY = 14; - private static final boolean DEFAULT_SYSTEM_INSTALLER = false; + private static final boolean DEFAULT_PRIVILEGED_INSTALLER = false; private static final boolean DEFAULT_LOCAL_REPO_BONJOUR = true; private static final boolean DEFAULT_CACHE_APK = false; private static final boolean DEFAULT_LOCAL_REPO_HTTPS = false; @@ -76,7 +76,7 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi public static final int DEFAULT_PROXY_PORT = 8118; public static final boolean DEFAULT_SHOW_NFC_DURING_SWAP = true; private static final boolean DEFAULT_FIRST_TIME = true; - private static final boolean DEFAULT_POST_SYSTEM_INSTALL = false; + private static final boolean DEFAULT_POST_PRIVILEGED_INSTALL = false; private boolean compactLayout = DEFAULT_COMPACT_LAYOUT; private boolean filterAppsRequiringRoot = DEFAULT_ROOTED; @@ -101,12 +101,12 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi initialized.put(key, false); } - public boolean isSystemInstallerEnabled() { - return preferences.getBoolean(PREF_SYSTEM_INSTALLER, DEFAULT_SYSTEM_INSTALLER); + public boolean isPrivilegedInstallerEnabled() { + return preferences.getBoolean(PREF_PRIVILEGED_INSTALLER, DEFAULT_PRIVILEGED_INSTALLER); } - public void setSystemInstallerEnabled(boolean enable) { - preferences.edit().putBoolean(PREF_SYSTEM_INSTALLER, enable).commit(); + public void setPrivilegedInstallerEnabled(boolean enable) { + preferences.edit().putBoolean(PREF_PRIVILEGED_INSTALLER, enable).commit(); } public boolean isFirstTime() { @@ -117,12 +117,12 @@ public class Preferences implements SharedPreferences.OnSharedPreferenceChangeLi preferences.edit().putBoolean(PREF_FIRST_TIME, firstTime).commit(); } - public boolean isPostSystemInstall() { - return preferences.getBoolean(PREF_POST_SYSTEM_INSTALL, DEFAULT_POST_SYSTEM_INSTALL); + public boolean isPostPrivilegedInstall() { + return preferences.getBoolean(PREF_POST_PRIVILEGED_INSTALL, DEFAULT_POST_PRIVILEGED_INSTALL); } - public void setPostSystemInstall(boolean postInstall) { - preferences.edit().putBoolean(PREF_POST_SYSTEM_INSTALL, postInstall).commit(); + public void setPostPrivilegedInstall(boolean postInstall) { + preferences.edit().putBoolean(PREF_POST_PRIVILEGED_INSTALL, postInstall).commit(); } public boolean shouldCacheApks() { diff --git a/F-Droid/src/org/fdroid/fdroid/installer/Installer.java b/F-Droid/src/org/fdroid/fdroid/installer/Installer.java index 77f3f9143..a6b725b31 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/Installer.java +++ b/F-Droid/src/org/fdroid/fdroid/installer/Installer.java @@ -19,7 +19,6 @@ package org.fdroid.fdroid.installer; -import android.Manifest.permission; import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -107,7 +106,7 @@ abstract public class Installer { InstallerCallback callback) { // system permissions and pref enabled -> SystemInstaller - boolean isSystemInstallerEnabled = Preferences.get().isSystemInstallerEnabled(); + boolean isSystemInstallerEnabled = Preferences.get().isPrivilegedInstallerEnabled(); if (isSystemInstallerEnabled) { if (PrivilegedInstaller.isAvailable(activity)) { Utils.DebugLog(TAG, "system permissions -> SystemInstaller"); diff --git a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java index c69292f55..a80c650dd 100644 --- a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java @@ -38,22 +38,20 @@ import eu.chainfire.libsuperuser.Shell; abstract class InstallPrivileged { protected final Context context; - protected final String apkPath; private static final String PACKAGE_NAME = "org.fdroid.fdroid.privileged"; - public InstallPrivileged(final Context context, final String apkPath) { + public InstallPrivileged(final Context context) { this.context = context; - this.apkPath = apkPath; } - public static InstallPrivileged create(final Context context, final String apkPath) { + public static InstallPrivileged create(final Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return new LollipopImpl(context, apkPath); + return new LollipopImpl(context); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - return new KitKatToLollipopImpl(context, apkPath); + return new KitKatToLollipopImpl(context); } else { - return new PreKitKatImpl(context, apkPath); + return new PreKitKatImpl(context); } } @@ -80,19 +78,19 @@ abstract class InstallPrivileged { Shell.SU.run(commands); } - final void runInstall() { + final void runInstall(String apkPath) { onPreInstall(); - Shell.SU.run(getInstallCommands()); + Shell.SU.run(getInstallCommands(apkPath)); } protected String getInstallPath() { return getSystemFolder() + "FDroidPrivileged.apk"; } - private List getInstallCommands() { + private List getInstallCommands(String apkPath) { final List commands = new ArrayList<>(); commands.add("mount -o rw,remount /system"); - commands.addAll(getCopyToSystemCommands()); + commands.addAll(getCopyToSystemCommands(apkPath)); commands.add("pm uninstall " + PACKAGE_NAME); commands.add("mv " + getInstallPath() + ".tmp " + getInstallPath()); commands.add("pm install -r " + getInstallPath()); @@ -103,7 +101,7 @@ abstract class InstallPrivileged { return commands; } - protected List getCopyToSystemCommands() { + protected List getCopyToSystemCommands(String apkPath) { final List commands = new ArrayList<>(2); commands.add("cat " + apkPath + " > " + getInstallPath() + ".tmp"); commands.add("chmod 644 " + getInstallPath() + ".tmp"); @@ -118,8 +116,8 @@ abstract class InstallPrivileged { private static class PreKitKatImpl extends InstallPrivileged { - public PreKitKatImpl(Context context, String apkPath) { - super(context, apkPath); + public PreKitKatImpl(Context context) { + super(context); } @Override @@ -131,8 +129,8 @@ abstract class InstallPrivileged { private static class KitKatToLollipopImpl extends InstallPrivileged { - public KitKatToLollipopImpl(Context context, String apkPath) { - super(context, apkPath); + public KitKatToLollipopImpl(Context context) { + super(context); } /** @@ -152,14 +150,14 @@ abstract class InstallPrivileged { */ private static class LollipopImpl extends InstallPrivileged { - public LollipopImpl(Context context, String apkPath) { - super(context, apkPath); + public LollipopImpl(Context context) { + super(context); } @Override protected void onPreInstall() { // Setup preference to execute postInstall after reboot - Preferences.get().setPostSystemInstall(true); + Preferences.get().setPostPrivilegedInstall(true); } public String getWarningInfo() { @@ -178,7 +176,7 @@ abstract class InstallPrivileged { * Create app directory */ @Override - protected List getCopyToSystemCommands() { + protected List getCopyToSystemCommands(String apkPath) { List commands = new ArrayList<>(3); commands.add("mkdir -p " + getSystemFolder()); // create app directory if not existing commands.add("chmod 755 " + getSystemFolder()); diff --git a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedBootReceiver.java b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedBootReceiver.java index 7f8598243..9a1cc0173 100644 --- a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedBootReceiver.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedBootReceiver.java @@ -30,8 +30,8 @@ public class InstallPrivilegedBootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { - if (Preferences.get().isPostSystemInstall()) { - Preferences.get().setPostSystemInstall(false); + if (Preferences.get().isPostPrivilegedInstall()) { + Preferences.get().setPostPrivilegedInstall(false); Intent postInstall = new Intent(context.getApplicationContext(), InstallPrivilegedDialogActivity.class); postInstall.setAction(InstallPrivilegedDialogActivity.ACTION_POST_INSTALL); diff --git a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java index b413cad0b..ece28975a 100644 --- a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java @@ -40,7 +40,6 @@ import org.fdroid.fdroid.FDroid; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; -import org.fdroid.fdroid.installer.Installer; import org.fdroid.fdroid.installer.PrivilegedInstaller; import eu.chainfire.libsuperuser.Shell; @@ -88,7 +87,7 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { Preferences.get().setFirstTime(false); if (PrivilegedInstaller.isAvailable(context)) { - Preferences.get().setSystemInstallerEnabled(true); + Preferences.get().setPrivilegedInstallerEnabled(true); } else { runFirstTime(context); } @@ -160,7 +159,7 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId()); String message = getString(R.string.system_install_first_time_message) + "

" - + InstallPrivileged.create(getApplicationContext(), null).getWarningInfo(); + + InstallPrivileged.create(getApplicationContext()).getWarningInfo(); AlertDialog.Builder builder = new AlertDialog.Builder(theme) .setMessage(Html.fromHtml(message)) @@ -269,7 +268,7 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { @Override protected Void doInBackground(Void... voids) { - InstallPrivileged.create(getApplicationContext()).runInstall(); + InstallPrivileged.create(getApplicationContext()).runInstall("test"); // TODO return null; } }; @@ -284,7 +283,7 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { final boolean success = PrivilegedInstaller.isAvailable(this); // enable system installer on installation success - Preferences.get().setSystemInstallerEnabled(success); + Preferences.get().setPrivilegedInstallerEnabled(success); AlertDialog.Builder builder = new AlertDialog.Builder(theme) .setTitle(success ? R.string.system_install_post_success : R.string.system_install_post_fail) diff --git a/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java b/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java index f87644e75..69c473651 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java +++ b/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java @@ -21,7 +21,6 @@ import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.installer.PrivilegedInstaller; import org.fdroid.fdroid.privileged.install.InstallPrivilegedDialogActivity; -import org.fdroid.fdroid.installer.Installer; import java.util.Locale; @@ -42,7 +41,7 @@ public class PreferencesFragment extends PreferenceFragment Preferences.PREF_LANGUAGE, Preferences.PREF_CACHE_APK, Preferences.PREF_EXPERT, - Preferences.PREF_SYSTEM_INSTALLER, + Preferences.PREF_PRIVILEGED_INSTALLER, Preferences.PREF_ENABLE_PROXY, Preferences.PREF_PROXY_HOST, Preferences.PREF_PROXY_PORT, @@ -150,7 +149,7 @@ public class PreferencesFragment extends PreferenceFragment checkSummary(key, R.string.expert_on); break; - case Preferences.PREF_SYSTEM_INSTALLER: + case Preferences.PREF_PRIVILEGED_INSTALLER: checkSummary(key, R.string.system_installer_on); break; @@ -183,8 +182,8 @@ public class PreferencesFragment extends PreferenceFragment /** * Initializes SystemInstaller preference, which can only be enabled when F-Droid is installed as a system-app */ - protected void initSystemInstallerPreference() { - CheckBoxPreference pref = (CheckBoxPreference) findPreference(Preferences.PREF_SYSTEM_INSTALLER); + protected void initPrivilegedInstallerPreference() { + CheckBoxPreference pref = (CheckBoxPreference) findPreference(Preferences.PREF_PRIVILEGED_INSTALLER); // we are handling persistence ourself! pref.setPersistent(false); @@ -199,13 +198,13 @@ public class PreferencesFragment extends PreferenceFragment if (PrivilegedInstaller.isAvailable(getActivity())) { // system-permission are granted, i.e. F-Droid is a system-app SharedPreferences.Editor editor = pref.getSharedPreferences().edit(); - editor.putBoolean(Preferences.PREF_SYSTEM_INSTALLER, true); + editor.putBoolean(Preferences.PREF_PRIVILEGED_INSTALLER, true); editor.commit(); pref.setChecked(true); } else { // system-permission not available SharedPreferences.Editor editor = pref.getSharedPreferences().edit(); - editor.putBoolean(Preferences.PREF_SYSTEM_INSTALLER, false); + editor.putBoolean(Preferences.PREF_PRIVILEGED_INSTALLER, false); editor.commit(); pref.setChecked(false); @@ -232,7 +231,7 @@ public class PreferencesFragment extends PreferenceFragment } } else { SharedPreferences.Editor editor = pref.getSharedPreferences().edit(); - editor.putBoolean(Preferences.PREF_SYSTEM_INSTALLER, false); + editor.putBoolean(Preferences.PREF_PRIVILEGED_INSTALLER, false); editor.commit(); pref.setChecked(false); } @@ -242,8 +241,8 @@ public class PreferencesFragment extends PreferenceFragment }); } - protected void initUninstallSystemAppPreference() { - Preference pref = findPreference(Preferences.PREF_UNINSTALL_SYSTEM_APP); + protected void initUninstallPrivilegedAppPreference() { + Preference pref = findPreference(Preferences.PREF_UNINSTALL_PRIVILEGED_APP); pref.setPersistent(false); pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @@ -281,8 +280,8 @@ public class PreferencesFragment extends PreferenceFragment updateSummary(key, false); } - initSystemInstallerPreference(); - initUninstallSystemAppPreference(); + initPrivilegedInstallerPreference(); + initUninstallPrivilegedAppPreference(); } @Override From 1fd85f40e7fd253884459f86dea25835dc9e319e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 27 Aug 2015 11:00:40 +0200 Subject: [PATCH 09/10] Install privileged methods --- F-Droid/res/values/strings.xml | 26 +++++++++---------- F-Droid/src/org/fdroid/fdroid/AppDetails.java | 2 +- .../fdroid/fdroid/installer/Installer.java | 20 +++++++++++++- .../fdroid/installer/PrivilegedInstaller.java | 10 +++---- .../privileged/install/InstallPrivileged.java | 15 ++++++----- .../InstallPrivilegedDialogActivity.java | 20 +++++++++++--- .../views/fragments/PreferencesFragment.java | 9 ++++--- 7 files changed, 68 insertions(+), 34 deletions(-) diff --git a/F-Droid/res/values/strings.xml b/F-Droid/res/values/strings.xml index 8c262df2a..3e72acb90 100644 --- a/F-Droid/res/values/strings.xml +++ b/F-Droid/res/values/strings.xml @@ -296,23 +296,23 @@ An error occurred while parsing the package Uninstall error Failed to uninstall due to an unknown error - System permissions denied - This option is only available when F-Droid is installed as a privileged app. - Install as a privileged app + Privileged F-Droid is not available + This option is only available when privileged F-Droid is installed. + Install privileged F-Droid Install privileged F-Droid? Touch for more information. - Touch to install F-Droid as a privileged app, tightly coupled with the Android operating system. This allows F-Droid to install, upgrade and uninstall apps on its own.\nYou can also do this later from F-Droid\'s preferences. - Successful installation as a privileged app - Installation as a privileged app failed - F-Droid has been successfully installed as a privileged app. This allows F-Droid to install, upgrade and uninstall apps on its own. - The installation of F-Droid as a privileged app failed. The installation method is not supported by all Android distributions, please consult the F-Droid bug tracker for more information. + Touch to install privileged F-Droid, tightly coupled with the Android operating system. This allows F-Droid to install, upgrade and uninstall apps on its own.\nYou can also do this later from F-Droid\'s preferences. + Successfully installed privileged F-Droid + Installation of privileged F-Droid failed + Privileged F-Droid has been successfully installed. This allows F-Droid to install, upgrade and uninstall apps on its own. + The installation of privileged F-Droid has failed. The installation method is not supported by all Android distributions, please consult the F-Droid bug tracker for more information. installing… uninstalling… - Do you want to install F-Droid as a privileged app?\nThis takes up to 10 seconds. - Do you want to install F-Droid as a privileged app?\nThis takes up to 10 seconds and the device will be <b>rebooted</b> afterwards. - Looks like you have root access on your device. You can now install F-Droid as a privileged app, tightly coupled with the Android operating system. This allows F-Droid to install, upgrade and uninstall apps on its own. - Do you want to uninstall F-Droid? - This will uninstall F-Droid completely. + Do you want to install privileged F-Droid?\nThis takes up to 10 seconds. + Do you want to install privileged F-Droid?\nThis takes up to 10 seconds and the device will be <b>rebooted</b> afterwards. + Looks like you have root access on your device. You can now install privileged F-Droid, tightly coupled with the Android operating system. This allows F-Droid to install, upgrade and uninstall apps on its own. + Do you want to uninstall privileged F-Droid? + This will uninstall privileged F-Droid. Uninstall F-Droid is an installable catalogue of FOSS (Free and Open Source Software) applications for the Android platform. The client makes it easy to browse, install, and keep track of updates on your device. diff --git a/F-Droid/src/org/fdroid/fdroid/AppDetails.java b/F-Droid/src/org/fdroid/fdroid/AppDetails.java index ee03cb40c..1adc96743 100644 --- a/F-Droid/src/org/fdroid/fdroid/AppDetails.java +++ b/F-Droid/src/org/fdroid/fdroid/AppDetails.java @@ -870,7 +870,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A private void installApk(File file) { try { - installer.installPackage(file); + installer.installPackage(file, app.id); } catch (AndroidNotCompatibleException e) { Log.e(TAG, "Android not compatible with this Installer!", e); } diff --git a/F-Droid/src/org/fdroid/fdroid/installer/Installer.java b/F-Droid/src/org/fdroid/fdroid/installer/Installer.java index a6b725b31..295032086 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/Installer.java +++ b/F-Droid/src/org/fdroid/fdroid/installer/Installer.java @@ -27,6 +27,7 @@ import android.util.Log; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Utils; +import org.fdroid.fdroid.privileged.install.InstallPrivilegedDialogActivity; import java.io.File; import java.util.List; @@ -146,13 +147,30 @@ abstract public class Installer { return null; } - public void installPackage(File apkFile) throws AndroidNotCompatibleException { + public void installPackage(File apkFile, String packageName) throws AndroidNotCompatibleException { // check if file exists... if (!apkFile.exists()) { Log.e(TAG, "Couldn't find file " + apkFile + " to install."); return; } + // special case: Install F-Droid Privileged + if (packageName.equals(PrivilegedInstaller.PRIVILEGED_PACKAGE_NAME)) { + Activity activity; + try { + activity = (Activity) mContext; + } catch (ClassCastException e) { + Log.d(TAG, "F-Droid Privileged can only be updated using an activity!"); + return; + } + + Intent installIntent = new Intent(activity, InstallPrivilegedDialogActivity.class); + installIntent.setAction(InstallPrivilegedDialogActivity.ACTION_INSTALL); + installIntent.putExtra(InstallPrivilegedDialogActivity.EXTRA_INSTALL_APK, apkFile.getAbsolutePath()); + activity.startActivity(installIntent); + return; + } + installPackageInternal(apkFile); } diff --git a/F-Droid/src/org/fdroid/fdroid/installer/PrivilegedInstaller.java b/F-Droid/src/org/fdroid/fdroid/installer/PrivilegedInstaller.java index 23830c26b..132a2e5fe 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/PrivilegedInstaller.java +++ b/F-Droid/src/org/fdroid/fdroid/installer/PrivilegedInstaller.java @@ -74,8 +74,8 @@ public class PrivilegedInstaller extends Installer { private static final String TAG = "PrivilegedInstaller"; - private static final String PRIVILEGED_INTENT = "org.fdroid.fdroid.privileged.IPrivilegedService"; - private static final String PRIVILEGED_PACKAGE_NAME = "org.fdroid.fdroid.privileged"; + private static final String PRIVILEGED_SERVICE_INTENT = "org.fdroid.fdroid.privileged.IPrivilegedService"; + public static final String PRIVILEGED_PACKAGE_NAME = "org.fdroid.fdroid.privileged"; private Activity mActivity; @@ -119,7 +119,7 @@ public class PrivilegedInstaller extends Installer { public void onServiceDisconnected(ComponentName name) { } }; - Intent serviceIntent = new Intent(PRIVILEGED_INTENT); + Intent serviceIntent = new Intent(PRIVILEGED_SERVICE_INTENT); serviceIntent.setPackage(PRIVILEGED_PACKAGE_NAME); context.getApplicationContext().bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); @@ -210,7 +210,7 @@ public class PrivilegedInstaller extends Installer { } }; - Intent serviceIntent = new Intent(PRIVILEGED_INTENT); + Intent serviceIntent = new Intent(PRIVILEGED_SERVICE_INTENT); serviceIntent.setPackage(PRIVILEGED_PACKAGE_NAME); mContext.getApplicationContext().bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); @@ -316,7 +316,7 @@ public class PrivilegedInstaller extends Installer { } }; - Intent serviceIntent = new Intent(PRIVILEGED_INTENT); + Intent serviceIntent = new Intent(PRIVILEGED_SERVICE_INTENT); serviceIntent.setPackage(PRIVILEGED_PACKAGE_NAME); mContext.getApplicationContext().bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); diff --git a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java index a80c650dd..181244071 100644 --- a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivileged.java @@ -24,6 +24,7 @@ import android.os.Build; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; +import org.fdroid.fdroid.installer.PrivilegedInstaller; import java.util.ArrayList; import java.util.List; @@ -39,7 +40,7 @@ abstract class InstallPrivileged { protected final Context context; - private static final String PACKAGE_NAME = "org.fdroid.fdroid.privileged"; + private static final String APK_FILE_NAME = "FDroidPrivileged.apk"; public InstallPrivileged(final Context context) { this.context = context; @@ -67,10 +68,10 @@ abstract class InstallPrivileged { final void runUninstall() { final String[] commands = { - "am force-stop " + PACKAGE_NAME, - "pm clear " + PACKAGE_NAME, + "am force-stop " + PrivilegedInstaller.PRIVILEGED_PACKAGE_NAME, + "pm clear " + PrivilegedInstaller.PRIVILEGED_PACKAGE_NAME, "mount -o rw,remount /system", - "pm uninstall " + PACKAGE_NAME, + "pm uninstall " + PrivilegedInstaller.PRIVILEGED_PACKAGE_NAME, "rm -f " + getInstallPath(), "sleep 5", "mount -o ro,remount /system" @@ -84,19 +85,19 @@ abstract class InstallPrivileged { } protected String getInstallPath() { - return getSystemFolder() + "FDroidPrivileged.apk"; + return getSystemFolder() + APK_FILE_NAME; } private List getInstallCommands(String apkPath) { final List commands = new ArrayList<>(); commands.add("mount -o rw,remount /system"); commands.addAll(getCopyToSystemCommands(apkPath)); - commands.add("pm uninstall " + PACKAGE_NAME); + commands.add("pm uninstall " + PrivilegedInstaller.PRIVILEGED_PACKAGE_NAME); commands.add("mv " + getInstallPath() + ".tmp " + getInstallPath()); commands.add("pm install -r " + getInstallPath()); commands.add("sleep 5"); // wait until the app is really installed commands.add("mount -o ro,remount /system"); - commands.add("am force-stop " + PACKAGE_NAME); + commands.add("am force-stop " + PrivilegedInstaller.PRIVILEGED_PACKAGE_NAME); commands.addAll(getPostInstallCommands()); return commands; } diff --git a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java index ece28975a..2fd978546 100644 --- a/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java +++ b/F-Droid/src/org/fdroid/fdroid/privileged/install/InstallPrivilegedDialogActivity.java @@ -36,12 +36,15 @@ import android.text.Html; import android.util.Log; import android.view.ContextThemeWrapper; +import org.fdroid.fdroid.AppDetails; import org.fdroid.fdroid.FDroid; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; import org.fdroid.fdroid.installer.PrivilegedInstaller; +import java.io.File; + import eu.chainfire.libsuperuser.Shell; /** @@ -52,11 +55,14 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { private static final String TAG = "InstallIntoSystem"; public static final String ACTION_INSTALL = "install"; + public static final String EXTRA_INSTALL_APK = "apk_file"; + public static final String ACTION_UNINSTALL = "uninstall"; public static final String ACTION_POST_INSTALL = "post_install"; public static final String ACTION_FIRST_TIME = "first_time"; String action; + String apkFile; @Override protected void onCreate(Bundle savedInstanceState) { @@ -70,6 +76,8 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { return; } + apkFile = getIntent().getStringExtra(EXTRA_INSTALL_APK); + action = getIntent().getAction(); if (ACTION_UNINSTALL.equals(action)) { uninstall(); @@ -166,7 +174,11 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { .setPositiveButton(R.string.system_permission_install_via_root, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - installTask.execute(); + // Open details of F-Droid Privileged + Intent intent = new Intent(InstallPrivilegedDialogActivity.this, AppDetails.class); + intent.putExtra(AppDetails.EXTRA_APPID, + PrivilegedInstaller.PRIVILEGED_PACKAGE_NAME); + startActivity(intent); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @@ -268,7 +280,7 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { @Override protected Void doInBackground(Void... voids) { - InstallPrivileged.create(getApplicationContext()).runInstall("test"); // TODO + InstallPrivileged.create(getApplicationContext()).runInstall(apkFile); return null; } }; @@ -304,9 +316,9 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity { // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId()); - final boolean systemApp = PrivilegedInstaller.isAvailable(this); + final boolean isAvailable = PrivilegedInstaller.isAvailable(this); - if (systemApp) { + if (isAvailable) { AlertDialog.Builder builder = new AlertDialog.Builder(theme) .setTitle(R.string.system_uninstall) .setMessage(R.string.system_uninstall_message) diff --git a/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java b/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java index 69c473651..00226f399 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java +++ b/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java @@ -14,6 +14,7 @@ import android.support.v7.app.AlertDialog; import android.text.Html; import android.text.TextUtils; +import org.fdroid.fdroid.AppDetails; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.PreferencesActivity; @@ -221,9 +222,11 @@ public class PreferencesFragment extends PreferenceFragment alertBuilder.setPositiveButton(R.string.system_permission_install_via_root, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - Intent installIntent = new Intent(getActivity(), InstallPrivilegedDialogActivity.class); - installIntent.setAction(InstallPrivilegedDialogActivity.ACTION_INSTALL); - startActivity(installIntent); + // Open details of F-Droid Privileged + Intent intent = new Intent(getActivity(), AppDetails.class); + intent.putExtra(AppDetails.EXTRA_APPID, + PrivilegedInstaller.PRIVILEGED_PACKAGE_NAME); + startActivity(intent); } }); alertBuilder.setNegativeButton(R.string.cancel, null); From b8b60d52bfb5da1c601e0d2c195f1703871a45ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 7 Sep 2015 01:32:41 +0200 Subject: [PATCH 10/10] Change privileged app name, versioning and icon --- F-Droid-Privileged/build.gradle | 4 +- .../src/main/AndroidManifest.xml | 2 +- .../main/res/drawable-hdpi/ic_launcher.png | Bin 4548 -> 0 bytes .../main/res/drawable-ldpi/ic_launcher.png | Bin 1986 -> 0 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 2664 -> 0 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 6033 -> 0 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 10295 -> 0 bytes .../main/res/drawable-xxxhdpi/ic_launcher.png | Bin 14497 -> 0 bytes .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 4206 bytes .../src/main/res/mipmap-ldpi/ic_launcher.png | Bin 0 -> 1873 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2588 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 5823 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 9382 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 12854 bytes .../src/main/res/values/strings.xml | 2 +- .../fdroid-logo-privileged.svg | 359 ++++++++++++++++++ media/fdroid-logo-2015/puzzle.svg | 1 + 17 files changed, 364 insertions(+), 4 deletions(-) delete mode 100644 F-Droid-Privileged/src/main/res/drawable-hdpi/ic_launcher.png delete mode 100644 F-Droid-Privileged/src/main/res/drawable-ldpi/ic_launcher.png delete mode 100644 F-Droid-Privileged/src/main/res/drawable-mdpi/ic_launcher.png delete mode 100644 F-Droid-Privileged/src/main/res/drawable-xhdpi/ic_launcher.png delete mode 100644 F-Droid-Privileged/src/main/res/drawable-xxhdpi/ic_launcher.png delete mode 100644 F-Droid-Privileged/src/main/res/drawable-xxxhdpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/mipmap-ldpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 F-Droid-Privileged/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 media/fdroid-logo-2015/fdroid-logo-privileged.svg create mode 100644 media/fdroid-logo-2015/puzzle.svg diff --git a/F-Droid-Privileged/build.gradle b/F-Droid-Privileged/build.gradle index 69289d7dc..d702ffd75 100644 --- a/F-Droid-Privileged/build.gradle +++ b/F-Droid-Privileged/build.gradle @@ -11,8 +11,8 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 22 - versionCode 1 - versionName "1.0" + versionCode 1001 + versionName "0.1-alpha1" } compileOptions { diff --git a/F-Droid-Privileged/src/main/AndroidManifest.xml b/F-Droid-Privileged/src/main/AndroidManifest.xml index 127de4e1c..5602cb3e2 100644 --- a/F-Droid-Privileged/src/main/AndroidManifest.xml +++ b/F-Droid-Privileged/src/main/AndroidManifest.xml @@ -22,7 +22,7 @@ M1 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 W!7{!k@hV3E0000bhm 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 WCEE79^Y#25Kwd^gx?0jK^nU=My12^# diff --git a/F-Droid-Privileged/src/main/res/drawable-xxxhdpi/ic_launcher.png b/F-Droid-Privileged/src/main/res/drawable-xxxhdpi/ic_launcher.png deleted file mode 100644 index c012986f5299366d0a00859626c75b4046c8b5c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14497 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 Ef;dy`?*IS* literal 0 HcmV?d00001 diff --git a/F-Droid-Privileged/src/main/res/mipmap-ldpi/ic_launcher.png b/F-Droid-Privileged/src/main/res/mipmap-ldpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4aec4b7828d387d9bae1c82d0ce57d64926f46b6 GIT binary patch literal 1873 zcmV-X2d?;uP)(^b8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H108(^CSad^gaCvfRXJ~W)Lqi}zbaZlQVs&(BZ*DD9Xkl_?L2PMj zWguvDbZ|N^FJp3LVRUJBWn*t`ZEtRKE^l&YFKlUJWo~n2b1!0fEpuTnGcGVMUV~b^ z000JXNkl6~}+yH#564&iWSLF9|7;T}vng6rv`oT45ntRiRN(h?EvV5f2qgP;Wx5cuJM36ll`MRhu-*h5Cl=#PP1zd!L!_ z@UR!}+HSLJIY*k+p38jaKj-_OGv6R0JSk6V5#d%|_2$q3?XR9lKKtrDFLI0Iw=eDc zyL;lfcs;QiVB(S)5A4fd|NYDN|7f$p{N}{yPx9*gfvXqwJN3ld0I$8y!NYC#h2H*4 zzk2PzhjLpx0?$+hDQ$$3!Ib`JjT8-ruo7v|Amw`#GhxAxeE7?`$t|;IPxm}f4+QeLRmWtCp-r*f~QJQB06IsOZG@9DpezuOQXfY%px zghr(`2#Ao&SeRTF+M6fp1uF^H01^s0MUd)6qVqJx{EFX}mf&mMH=KIFK#4o<#$(n0fm|z4FN)=QtnQDfUejV z0qAeJlQu?cfK+dnXGR$67y}ern?~q&zEQP(jlfx5AqguBrPX+qJs@j+Pz9wri%_sX zCLbg!mK5hIJ|jUxfb41|mkA4AOrii;F7oE}gLK;WaV>b6yqbYkK+3w2EN>?6p-(-? zV)zD2>WxZNHe+%d26X;EO@G|EEB`&)!4ZUI{>e0NmC{#nsMHA6q+aF%b39(M+8}~o z(EimAV#oPx{eWt^Y;<(gcJ4TQ#BKHV6unAdW%gjIYh*ym{<5idGgAxce>?BL^x~;g zr|RCfnhME%zkVSRM#c)JRDspJtkR`YrBW}HLn@<4h;}HvuiW_;;9DC46wlj-GKH17 zTf-OuKeyiAzRfCAm*p_^NIiteHsvAj+~TV9M(hLS@r{)U4}=HEU(w7)N+WmbIgw~Vscr$p%H>qio(n!#t#rcX-#Bc8}9boNPl!5 z9bd$5Yp?KXBT_pUD`Z|dF!}K~c2_SVhWzv-A`lteMx?h7QHtEuBqj)Ox_Sr_i8Wv} zg@yptRLIEMIczd%oZdb}AiCo=v=afl_^uRfk)NI-NG8!u9{KC@L`pY%(It+4^%yaG zM*r?@|Jg_Or;lx@LX|cyUB(D#jj}9s)CH^f3<4>L=vTh-#Dda4p6cPrCbizqu^Yb5mDfRTHSE%x{(rr#x zH-0=$es-2fZ!cC$D}HhP$6lAYlVxZ%~CxTf|?1%xObzNVr8j6T6 zZdsL8xgPHD2!**>a?>-IeDOq~T^GBh6}!E?AwZuBwpvlCxhp2tH-s*AQWYwtHPQY7 z=pR7B5R^jcVu2^-cQZBn4!xZdIF5hQq)J1?3wh>WTaM;^-u>}i>BI3Z$@SLSw6;Hq zvX;l)yOk{w0N;t6eRw#zQ1(A_#=YJ3*Z~k4vv71*;p{C1v{~|h^#GllWFED100000 LNkvXXu0mjf-GFdU literal 0 HcmV?d00001 diff --git a/F-Droid-Privileged/src/main/res/mipmap-mdpi/ic_launcher.png b/F-Droid-Privileged/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..b565888382d493015ff47cfc8ecd93bc6c8bde25 GIT binary patch literal 2588 zcmV+%3gh*OP)&fulsItOPc0gD18XUmKG==ihxB%8Ggu=sfY|d%2e%- z`h)5q{y@c%X-64kq{55?jDohpfR8fHC@A7Ur8UJCgtj!0rcH7al6!NL^FDj|o~K-36;r;~@C+3=u6uil=`PFyuxU%|}$+FzUR8X1h6 zE*)O_^XG1Ssu3XT$wPZ?yeZHQZMCN~KJ>~t_s-Uzm>EPwH-B~Q=JgxKb|q6P!Mf-x z%P)8SVo;FypbjKN*&=e!_`?o+{Q8Rt(?}kFd&+yyIJ~cYckdq~Up##H@R@f~Bme+J z*Qj^g{r;m@UTfX4{DKv%L@i3v9O`SvSLaUb*xGdQi@SRd z&K5i{orQ{W?AX4%-aKqng7-av>_`mO&u0svT?T#p`ObIsAO(mAcTwEZ4L)Fu!F zdYZ3Cn{sOv2+v_<9tlV)f?+Tc>Jmh>@Bp>M*M@+H!O!T@k=0Oy5%OIWy|nym0D!!e zm-9wIvd`sUruZ$4TH*C|!g>m*0k{&_IR6=w?m*breWEH-ft(8F1|O(eRgT4OEWwfT z4;-Aj16|HHkk;4YJ?n7{^RGfcYmI(E8{pN6o6w_fLsDIeK6@9kcp+pf1H$0(#4&tq zZUjPUl!)lZe`^0-_e$qRJ?fW=irU$x9{75xvqA@k=Ln1s>BEm~S=qIJ|9)>S1VRyD zX1;FIMcXdBVan-P;$8+t8f9%&BxJ>Vc)uv=IZQ&9+H)EG?IZte{>gy@2mHB!2Pz^^ zl$-AVN4Fi&*8xs|M6F2MC*Tecwo#zdl+DS@Y3@T zSSAA7hR}3SGy-8ns(s7IaA~Rmab1xeX?Nj^+t$pw4gzXqp$V5-%Slznw%8O{ChQaa zVB0R(5P{`%qY%*BI-sW0Rp2Z8opb_`&E!7`;MsX0ASI|~W-pru&hQYtkqpQ%pmlaZ ziN!&N0rp%3rU^frgFVm>B|8qIvm2yoWz&eO`V0b&&jox<0#$&^bpYJV5WLJVlyh2O zEN%mcAblUflnK%_D5<8xv!Ds~KtJsMK17x-4}qW0Q+O4DVkuPqUKDAWa5EXG=`@VC zc1YKSJ9rX)ZlVN^bOT0LH{F*8 zG#y%72c+-8K7I^dHWwOM={hiv9YHXehmuM`O{d`u4uXSV-oe)=Q1KMM8cdlGP0b)7 z;0_HTa9n^0dS@467py|0s~e>2008?$KfnwveNMsGG;4y_6bq&&=dTtD>P;Wp23SHw zqhJPh!k~c7>Ww>_&Z?NMPQi)dn#ltkw}*MYh7>@pILW5S`%+!%3AQ9 zM-Gg=ap$_pLuXAuN=D_)3Ns)b8_W#S3)O`ZPn6oq)1*iw0U^MFgtQ${GzOvR2rL`g zbbqP%D7J0-GE&JLd{1C}$X(_6Vh4a5W=o*X6hi0$0Ma9cb>TPw0C)6#xS0%s$$V(N z`1uKNP^cLwVicy2>q10k3fybgJ%Lm*2LMntiPS<5?9+ya4^i`M3DiiVwO5#kL;w=- zEfXS{g0xMzqoV*3jE*j-sU*CKJiN>>7!0B75RoVX(*l^G#G<9XSM=-)^=-rg01!S$ z<3yAzAz}W&gHBZ`(Y3wTCq*qqrhL&^$B%+t50T|70V!b}eH+qsE7ES^C34>RP!dU8 zw)jDO>Z)fDi&-U`WU~WR3uDWT=l~EDhtM$<={aJMRQz=7`pKPVOrUdnuTMg)o?0mE z1Ln~q(9&t>9bJWe;N(g86S)#_VHnUmd!WSQXpil~-Cx^0=gZ2mK?ByL>Z>G|Y`MZb zS<9w+BRfrw7SR~AmR7jKLts*1w6(!F_gv_{59v4{O$TX(rRwK$xMuw?&g!N$mhxdu zsw!#t1b~`Xo^?x!0-0(ydTT3~CESq={Co~t%OZ$q93mD6doKK37JfDhKRXU1Hs^B+ z0Dz|F0TJpBLp1>om@95MLNth=x3xp0n&6yx4|aclNnZ>fDGH3vZiv{NYqT?#Y65n4 zl;ew9YZ;dZM2W=^Tk#R_^m#x|p9e%N3SmTQxi>_r7IF8j4{VnUFT78xaRv1wcSe$o zjU$;D!$nJ9!qw|`BbA)pnMDQ!*A@tTF`ggS`U9W#s!R`TxiX)rNdN#Aty-0cEnIy) zwXM5F3N3n849X;#%xm|4@4Gh$A?GwI%)n4z3{uj-O9N9&c5mbWsB@@ql>Byx{-7xM z>|FhGBRVFt8q}!#{FaN&UjsEtiN*;L5!Red53XHEE(-bY6m_Rfqw^(u1}G|2Y!wPR z=Hf2{!emy1>j>zEe0K91_qAeML#NR00cE>T_;#W2c|@4?dU9=nu~QKUmG=AyMQuYPz>+?$81lk;?J^(;rTzdi6M}%CsQm1mYpo}1*?cHds8W1SAUC43@6*fC zn7==o2)?96WK%tR=KA*ljU`a$v-vR%PE!8BFx8x19J{G|JX+^9C?IRd^r^AO42jh$?j+cM$J zz$3G0GdZqdGOI!;$jD2~z4gA)@Qv)TgOO!UKzD&ePf;fn*}HkQ_3cXAUHjwrk-#Oz ycSXo|BRcQ6?E?E)z5YMcowyP5A@0PDk^chfCBk26xg?MP0000Da*Y0X}rPW)qEz7o?*kDM&4z^Q>m5?TZ6jIVSr6Cjw z;ZaB-hrUiz+BDEYfkO@_yxNch4Gk$I<)oqXK--XnU?*{~3D`A>pOT+?OS{_Fea_cE zR@(QycUQ5rmc!3ykMF(n&CEC7cjudLzL`5>M1F< zr3XKB(|3-J{tRy$@gDjiqimq_ze11Zr`pgX1yE$1_uZE z{(XU8jh<{tI*tT@kaqTJT^-6}AG_ym&5Oyv`2fZkyXQMMyi*FC{fI7x004=pFeXkn zJsA)}SHDwW z5RMx6C7pc?Aeg#>(c#vieY@Je8p<{={un?+V$v{D`=3!BJw2>`KRy)(0N6AMM>%@+ z*B{mHT5Ma`C|vs&mxQ`I)E}hinI=Gh1jE_k_Vl3_TJB_a_|*RWrm>jy=Y@K9-#*=D zO=ouhB=m)m;qU=HE9d%wID$|pap#vGy6L(LZ9HI%NpF9{MGt1!-T{Zw0D#Gn7!AJ^ z`NG&}_<3U{I0HPjs6BucPsA9zSz5E{WP5w3*s|mL?7yzMXfh_r0t^bm?24HYJ^O~O z+l*dW0vKa#<@W7?CX4rNc~k0+^{>f%__wa^M8k5TN|JNRzq9>oUu>_FI9}p2S z#`J-$TSxXhq1^X|9UWI{Vg2GM`&S^8zYxW(D;Iw)0$c)RkOz%8fiydYbr)TN$G$QB z_vyHLK%(RfJ^9>{2p@2X1rZS)-Lof6q@G!K3DalAOWwk-NFf)iUP)KIyjo0%OPO_A zY@1TZN(XS+)y-#Ak(oGn@Sx?N>)fHD2h4+rob~Is=~5`s@A%pLqE@F8GO|etw#6YS z1T|tsEu&5S(UzA@fIbp@v@oCiV}Equ?O99 zxGI1##@24$%!s9nrsD3xCt{c$QNf&ctO#F*mcT`rHBVqXxet?>lW6TRAj!3umHJ>? z98)72LcAYqB3lsAR$)5xB1UJP!(@6AZ9O__ah{oy>DKjEExDWRssI2Gjx)!Q_gfDD zsTl>U!+(J7tM7&?g$renjTg?|i(gND5wWgx4J_5Cq~uf>mv#RYUfXj!I4expO(%h$ z9sf(5o%s%;t!CA{CAB)l4I{PW3h)&SY#}@d>=H z?QZDVoPb{b+n>v$rzLFdz6Y1~e!N8Z0H8|Ec=P&y!V3A_5W-)sM2(qb`YM2k72j0% zcC0RJUG+Df4cz$#JcwSD1YM%$ocjOdKR?|rg5>mC?Bd^*E2v^3>cUf{5-OB1V@wK@+@a8y9=Yve_-LJr!sBC`8P~v_IcKO zDDh?JG+g(LdZ|!D4`4+aaGT8%j+mdsiR7bI%NWZ%i(jR013bbRl>+it2EoBEvbSO~ zySFOU@!5xP)cRZ3{KeOn$uk}mE*gBtfNYYFhnk$QJ4LPm4rOq__#>RwA4Hpc4Wh~h zr0ro$+q*H2hv6lBw=%2Wm!@TD2+yQ~Tyxj{}Yut(V>RrmdEb;9yjI8>8ae zC`8KL*8$3}XT~(~{Qq=3*W5h5=<)w@xSAj$q7KfjpM1Cd{;^Ym#O#y;+h%ZUSoMK= zA;R|>glnCs`O}eLFftM*P6cuDQ1}OD4rx>S_U&781$g#=XEn{b_$5C4^Phx1wRs2K znTpG8i~*ecdnz>zdY)?trDc1jRZJ4SL)!#E%tid;zky9A6{}-)KdXKK?$J@T8Y^mjI#)XtWZgiXnBDXIW{MqGal!XGtnIi zC7xWOCCGC4&xGfeD6jdfXX^5-&_UduR(7Sdhv)yP2k3s8}d+;6EY)s>g>=q)ip zjx%gK=F{rrflvSVbGJ4`_&|+4;4SwYydw|{e9ji6=oY~i?s;5OJOr74=A#TRR*Tar z^HpZlWCl&t44 zXp5l?&KY{5%DQNz{Q(RPUJGE!dxG~&cyLfsg3W(&V%pN&gzplmcAqm>=?N7=5~6~} ztBl&yiajF05rorm6A6P~we8aP^*3VYpJxx)oJ^{5OL?s>_RDiUKLBK#E48&`Q{o6EMcc0O0__L3Vf;YIiS` zjt*DeOYVJJvGk~`2b80x0htK;$>9>=%U#`2JG&}rJ<4Z{LFwp()DnX}JOq)=fJnd? zISnW>l$KcCcK>`p%?hZM;c_zL>=}quDtE&e)V|e_qs?hm%PmbLd5g zOkwGkBnetiZ~opqJ5n->J`d$xff_bu`D0$_#e%eE;`wW-vm3=*l2SQF#!Z+(^W z=l|DF4bORIImj(B@K6XufUqq%soAQ0pO0@pus|=!H)tpXD4onTTH=snu|k^Tz!({+ zkO)^)NG&l)kqEdJfMaCg#AjemO_k6&x&dS447A>rg+?^T;G}as!;a5Finf&T>)$4^ zm|2$i^(+9$-5}eqT6L zgnD#6f6bf1WuIvgl=i~Ji9k@>I>1!5m?RG=5`o&;1!Huyl&^FOvXbjrOjW^D4Z_p` z#{tvht>i$+ZnLo{KaR2iMdRI+4wm z@K(};tm^A3oC|#L`rEO6+b+bq4K#O{=vbwrW2FvBnd6sm_1B&Y-B}aU=KwD|`ZvEI zQ?f8q$GcN)LB~zmC3NMVixXASl;N%0zlKX*wF~8;Ej8$%V?}oELqY%yx7W!2%SK%a zC>OR{W4Ws2g(zI!Mz58$if6V1M=$-(iwA=x_rfv@P`Yg%EAc zZL1T4b${~^>vbhQho~VMDj4ehc%;bwl2v-xNapyll0lkr2CZ*Rg+L4S6U>Qml&lSa zz(Yk*R04!iP!N|ZkNDZpw+EbikF8ph15DUMx%}l`iQq zawH0}%>2*M4d};@LD;3=N6fpt_G|*?c+LYVY=2~sf}uG&fJ`&*mNHqcI_`A0AM@o~ zQI~!)P)iS}VKtzv&`4x1FTqOALM4IuzAg9n+VO!7-ABNP@0x28?4{8vZ zEUb7O_S^zavBg(9a&GIq$+2g1t|Wti5($G*rAyCQeH$LKDOuXGWsB=+S^L(m73X3n zo$J0J#u)3r^wMVg>if=cB^atoREFZBvO~E@B>-qERzYcN&(Q#|rl(+>I_a9X1z&dy&}ed#QdAv3E$PfGx&%K=>em1iPbZofSF!I~;4 z=c^W?TD_lQNU<2W7R=FG7R-^-@l5IJhSJ@G@~t>--=pzR7@_qWOU9S=T~Fh8-}Vr~ zF$-!yKvvyCHMEthAdD=WtPZkmNWmajFjUo} zAri1o4WqYbWFhRI8!$i%I>=Z#{sfu3u&^xX!$SzL3CMCo0+@M7QW2xHFl%y7Ops@|ngLpWKcuFnyqPh^ zMvysjC_hLS%JCRq95J_q`D=(wEvK$557f6YYazV>03-?8x&h$S$-G}LG8tr#AIojb zYHooXiGpbwSkajo!nPpNncT*#L>yFnbPKyM&XTR+r~=d-nXN|67(<|MHLP$L=IB`n zb8b&)HVZSGg*iHB&pFR+O|;!l4v->Igw{q~)0Y!`6~L(Ki9vbPqZ%SWjxs zgEci(DQF=owx`cSYHEVo)e9*S1`8zXsQLVbzXEJME|hR&p%ql^Je))A?t$9f1CdF? zo=xOpMz#fES%45=k_4`5V2TPUI=4N&N|0^2!}mjNF?;4&QlqO#QoTs?sCSs)p(d!I zvX3rv@wQh4Jiig!vSmwXX2syO*2=5CD*~-5DW!sH)fJJ{I28?uy(g0{Du#Ko(g z$Ho17An~PfPqQgG7m@$~!r5$Edd$d5Nr^!aa0m{6`i?ipk9(EjrvN3RX}y`gou6=8 z20jAD>d)?d3spUZ-S$?XE312|3gUF4q(tZ4{cL)BLYL{;`&TmTib3b8Lq36T$ppfsEmY zAKjj+8mg$}GgUsYb!%8L(B(+z0z;Gm3N`4AwOaAMe>il*MVk}vX;l5`gpBxj;mB24 zrT2e$OZuDTbhU&c1Y;~UFz^-wZPQ~ikz!lgc`bYZ2xyc6&@crA!w%x(g?mAC3xN6+ z0OXVaz?l0j3p_H)8gl;6Jh(*QoC;=$*dD#jjZ3XS;>L1l0;P(_%B!m z5aHTJ)}NUzH7;BgKdnZ0K`P*}G4>k9@TZNc-!eFo(}jtvqKc8`l}6R0g)cY-JUYRy z6C6JVp|+{}IRpuYR9wNtsbGGRs%YYLsM&tU&KM=CxKby0z2%%-h?^HFEf}K2vQZlsH1f@b&zI2E>nq z&0raG`<+zr-yhnNd3(KOTyQ36xnbG%fR_WJ+(1c!LD2-b)HpNz%2EIU$r&Z@p~x!5 z8K?b<=ENc~>(!FH^x>6Plmezk0?^YE6jh9cTFei;d%*tB`LstSSeOJ3Gmf66|C4|HL|2)zhES*D=Y40uTt*1Q+8NAQKFM@5oe7|?uDgXdXUGiM+ zD~1pZoYM=wgoL;+4RYVD7}>(!BremG2e~VjwE_|o>b<63dlMwi4xfv9NdPlrTFJ*l zs^;ukNLkC;3u?P8bKm%$rVoa~_N8jT@%87awrxzm07Hvy@U^zZO8)u}5rb_qWM*a9 zRzdMvlQ^(?qxHZ-+OVt@uoL9m-xR*i$Vd;QXXR_p#qlWb=%9N6+Dr4+lXDI`nl}D*ym)+mspuaNR>gY_*YAw?U@rM=1i3z@M$P++e`|ksKAS z;{g{etA)(x-`P*Y^>JK^Wg88>P_V2A;R^x3Q9y(78wE5N{||uY{=$yX7i|Cl002ov JPDHLkV1jAG{n`Kk literal 0 HcmV?d00001 diff --git a/F-Droid-Privileged/src/main/res/mipmap-xxhdpi/ic_launcher.png b/F-Droid-Privileged/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..bf34082d3466ce4db66da9988623f389935bbde4 GIT binary patch literal 9382 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 literal 0 HcmV?d00001 diff --git a/F-Droid-Privileged/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/F-Droid-Privileged/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..246c8094f433e91c84c9ab733ca2e5bb48e087fb GIT binary patch literal 12854 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 E4`#xw8~^|S literal 0 HcmV?d00001 diff --git a/F-Droid-Privileged/src/main/res/values/strings.xml b/F-Droid-Privileged/src/main/res/values/strings.xml index e375b6e4c..50777a72c 100644 --- a/F-Droid-Privileged/src/main/res/values/strings.xml +++ b/F-Droid-Privileged/src/main/res/values/strings.xml @@ -1,6 +1,6 @@ - F-Droid Privileged + F-Droid Privileged Extension diff --git a/media/fdroid-logo-2015/fdroid-logo-privileged.svg b/media/fdroid-logo-2015/fdroid-logo-privileged.svg new file mode 100644 index 000000000..d8cf2fc8f --- /dev/null +++ b/media/fdroid-logo-2015/fdroid-logo-privileged.svg @@ -0,0 +1,359 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/media/fdroid-logo-2015/puzzle.svg b/media/fdroid-logo-2015/puzzle.svg new file mode 100644 index 000000000..1ed0d45f4 --- /dev/null +++ b/media/fdroid-logo-2015/puzzle.svg @@ -0,0 +1 @@ + \ No newline at end of file