Add Privileged F-Droid project
This commit is contained in:
parent
d530a1cf56
commit
e87693d989
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
}
|
33
Privileged-F-Droid/.gitignore
vendored
Normal file
33
Privileged-F-Droid/.gitignore
vendored
Normal file
@ -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/*
|
51
Privileged-F-Droid/build.gradle
Normal file
51
Privileged-F-Droid/build.gradle
Normal file
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
Privileged-F-Droid/src/main/AndroidManifest.xml
Normal file
33
Privileged-F-Droid/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
package="org.fdroid.fdroid.privileged">
|
||||||
|
|
||||||
|
<!-- These permissions are only granted when this apk is installed as a privileged app! -->
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.INSTALL_PACKAGES"
|
||||||
|
tools:ignore="ProtectedPermissions" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.DELETE_PACKAGES"
|
||||||
|
tools:ignore="ProtectedPermissions" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="false"
|
||||||
|
android:icon="@drawable/ic_launcher"
|
||||||
|
android:label="@string/app_name">
|
||||||
|
|
||||||
|
<!-- API -->
|
||||||
|
<service
|
||||||
|
android:name=".PrivilegedService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true"
|
||||||
|
android:process=":fdroid_privileged"
|
||||||
|
tools:ignore="ExportedService">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.fdroid.fdroid.privileged.IPrivilegedService" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
@ -0,0 +1,305 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* <p/>
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
Privileged-F-Droid/src/main/res/drawable-hdpi/ic_launcher.png
Normal file
BIN
Privileged-F-Droid/src/main/res/drawable-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
BIN
Privileged-F-Droid/src/main/res/drawable-ldpi/ic_launcher.png
Normal file
BIN
Privileged-F-Droid/src/main/res/drawable-ldpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
Privileged-F-Droid/src/main/res/drawable-mdpi/ic_launcher.png
Normal file
BIN
Privileged-F-Droid/src/main/res/drawable-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
Privileged-F-Droid/src/main/res/drawable-xhdpi/ic_launcher.png
Normal file
BIN
Privileged-F-Droid/src/main/res/drawable-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.9 KiB |
BIN
Privileged-F-Droid/src/main/res/drawable-xxhdpi/ic_launcher.png
Normal file
BIN
Privileged-F-Droid/src/main/res/drawable-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
Privileged-F-Droid/src/main/res/drawable-xxxhdpi/ic_launcher.png
Normal file
BIN
Privileged-F-Droid/src/main/res/drawable-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
6
Privileged-F-Droid/src/main/res/values/strings.xml
Normal file
6
Privileged-F-Droid/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<string name="app_name">F-Droid Privileged</string>
|
||||||
|
|
||||||
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user