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 000000000..88138a47a Binary files /dev/null and b/F-Droid-Privileged/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/F-Droid-Privileged/src/main/res/drawable-ldpi/ic_launcher.png b/F-Droid-Privileged/src/main/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 000000000..f1e8bc847 Binary files /dev/null and b/F-Droid-Privileged/src/main/res/drawable-ldpi/ic_launcher.png differ diff --git a/F-Droid-Privileged/src/main/res/drawable-mdpi/ic_launcher.png b/F-Droid-Privileged/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..18ef68deb Binary files /dev/null and b/F-Droid-Privileged/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/F-Droid-Privileged/src/main/res/drawable-xhdpi/ic_launcher.png b/F-Droid-Privileged/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..98cb52a3e Binary files /dev/null and b/F-Droid-Privileged/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/F-Droid-Privileged/src/main/res/drawable-xxhdpi/ic_launcher.png b/F-Droid-Privileged/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..9d29cc939 Binary files /dev/null and b/F-Droid-Privileged/src/main/res/drawable-xxhdpi/ic_launcher.png differ 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 000000000..c012986f5 Binary files /dev/null and b/F-Droid-Privileged/src/main/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/F-Droid-Privileged/src/main/res/values/strings.xml b/F-Droid-Privileged/src/main/res/values/strings.xml new file mode 100644 index 000000000..e375b6e4c --- /dev/null +++ b/F-Droid-Privileged/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + F-Droid Privileged + +