Check if PrivilegedInstaller is available, adapt InstallPrivileged
This commit is contained in:
parent
976d06ea1a
commit
57af421561
@ -308,8 +308,8 @@
|
|||||||
<string name="system_install_post_fail_message">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.</string>
|
<string name="system_install_post_fail_message">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.</string>
|
||||||
<string name="system_install_installing">installing…</string>
|
<string name="system_install_installing">installing…</string>
|
||||||
<string name="system_install_uninstalling">uninstalling…</string>
|
<string name="system_install_uninstalling">uninstalling…</string>
|
||||||
<string name="system_install_question">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.</string>
|
<string name="system_install_question">Do you want to install F-Droid as a privileged app?\nThis takes up to 10 seconds.</string>
|
||||||
<string name="system_install_question_lollipop">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.</string>
|
<string name="system_install_question_lollipop">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.</string>
|
||||||
<string name="system_install_first_time_message">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.</string>
|
<string name="system_install_first_time_message">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.</string>
|
||||||
<string name="system_uninstall">Do you want to uninstall F-Droid?</string>
|
<string name="system_uninstall">Do you want to uninstall F-Droid?</string>
|
||||||
<string name="system_uninstall_message">This will uninstall F-Droid completely.</string>
|
<string name="system_uninstall_message">This will uninstall F-Droid completely.</string>
|
||||||
|
@ -109,7 +109,7 @@ abstract public class Installer {
|
|||||||
// system permissions and pref enabled -> SystemInstaller
|
// system permissions and pref enabled -> SystemInstaller
|
||||||
boolean isSystemInstallerEnabled = Preferences.get().isSystemInstallerEnabled();
|
boolean isSystemInstallerEnabled = Preferences.get().isSystemInstallerEnabled();
|
||||||
if (isSystemInstallerEnabled) {
|
if (isSystemInstallerEnabled) {
|
||||||
if (hasSystemPermissions(activity, pm)) {
|
if (PrivilegedInstaller.isAvailable(activity)) {
|
||||||
Utils.DebugLog(TAG, "system permissions -> SystemInstaller");
|
Utils.DebugLog(TAG, "system permissions -> SystemInstaller");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -147,17 +147,6 @@ abstract public class Installer {
|
|||||||
return null;
|
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 {
|
public void installPackage(File apkFile) throws AndroidNotCompatibleException {
|
||||||
// check if file exists...
|
// check if file exists...
|
||||||
if (!apkFile.exists()) {
|
if (!apkFile.exists()) {
|
||||||
|
@ -29,6 +29,7 @@ import android.content.ServiceConnection;
|
|||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
@ -84,7 +85,54 @@ public class PrivilegedInstaller extends Installer {
|
|||||||
InstallerCallback callback) throws AndroidNotCompatibleException {
|
InstallerCallback callback) throws AndroidNotCompatibleException {
|
||||||
super(activity, pm, callback);
|
super(activity, pm, callback);
|
||||||
this.mActivity = activity;
|
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
|
@Override
|
||||||
|
@ -38,18 +38,22 @@ import eu.chainfire.libsuperuser.Shell;
|
|||||||
abstract class InstallPrivileged {
|
abstract class InstallPrivileged {
|
||||||
|
|
||||||
protected final Context context;
|
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.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) {
|
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) {
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
return new KitKatToLollipopImpl(context);
|
return new KitKatToLollipopImpl(context, apkPath);
|
||||||
} else {
|
} else {
|
||||||
return new PreKitKatImpl(context);
|
return new PreKitKatImpl(context, apkPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,10 +69,10 @@ abstract class InstallPrivileged {
|
|||||||
|
|
||||||
final void runUninstall() {
|
final void runUninstall() {
|
||||||
final String[] commands = {
|
final String[] commands = {
|
||||||
"am force-stop org.fdroid.fdroid",
|
"am force-stop " + PACKAGE_NAME,
|
||||||
"pm clear org.fdroid.fdroid",
|
"pm clear " + PACKAGE_NAME,
|
||||||
"mount -o rw,remount /system",
|
"mount -o rw,remount /system",
|
||||||
"pm uninstall " + context.getPackageName(),
|
"pm uninstall " + PACKAGE_NAME,
|
||||||
"rm -f " + getInstallPath(),
|
"rm -f " + getInstallPath(),
|
||||||
"sleep 5",
|
"sleep 5",
|
||||||
"mount -o ro,remount /system"
|
"mount -o ro,remount /system"
|
||||||
@ -82,26 +86,26 @@ abstract class InstallPrivileged {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String getInstallPath() {
|
protected String getInstallPath() {
|
||||||
return getSystemFolder() + "FDroid.apk";
|
return getSystemFolder() + "FDroidPrivileged.apk";
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getInstallCommands() {
|
private List<String> getInstallCommands() {
|
||||||
final List<String> commands = new ArrayList<>();
|
final List<String> commands = new ArrayList<>();
|
||||||
commands.add("mount -o rw,remount /system");
|
commands.add("mount -o rw,remount /system");
|
||||||
commands.addAll(getCopyToSystemCommands());
|
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("mv " + getInstallPath() + ".tmp " + getInstallPath());
|
||||||
commands.add("pm install -r " + getInstallPath());
|
commands.add("pm install -r " + getInstallPath());
|
||||||
commands.add("sleep 5"); // wait until the app is really installed
|
commands.add("sleep 5"); // wait until the app is really installed
|
||||||
commands.add("mount -o ro,remount /system");
|
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());
|
commands.addAll(getPostInstallCommands());
|
||||||
return commands;
|
return commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<String> getCopyToSystemCommands() {
|
protected List<String> getCopyToSystemCommands() {
|
||||||
final List<String> commands = new ArrayList<>(2);
|
final List<String> commands = new ArrayList<>(2);
|
||||||
commands.add("cat " + context.getPackageCodePath() + " > " + getInstallPath() + ".tmp");
|
commands.add("cat " + apkPath + " > " + getInstallPath() + ".tmp");
|
||||||
commands.add("chmod 644 " + getInstallPath() + ".tmp");
|
commands.add("chmod 644 " + getInstallPath() + ".tmp");
|
||||||
return commands;
|
return commands;
|
||||||
}
|
}
|
||||||
@ -114,8 +118,8 @@ abstract class InstallPrivileged {
|
|||||||
|
|
||||||
private static class PreKitKatImpl extends InstallPrivileged {
|
private static class PreKitKatImpl extends InstallPrivileged {
|
||||||
|
|
||||||
public PreKitKatImpl(Context context) {
|
public PreKitKatImpl(Context context, String apkPath) {
|
||||||
super(context);
|
super(context, apkPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -127,8 +131,8 @@ abstract class InstallPrivileged {
|
|||||||
|
|
||||||
private static class KitKatToLollipopImpl extends InstallPrivileged {
|
private static class KitKatToLollipopImpl extends InstallPrivileged {
|
||||||
|
|
||||||
public KitKatToLollipopImpl(Context context) {
|
public KitKatToLollipopImpl(Context context, String apkPath) {
|
||||||
super(context);
|
super(context, apkPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,8 +152,8 @@ abstract class InstallPrivileged {
|
|||||||
*/
|
*/
|
||||||
private static class LollipopImpl extends InstallPrivileged {
|
private static class LollipopImpl extends InstallPrivileged {
|
||||||
|
|
||||||
public LollipopImpl(Context context) {
|
public LollipopImpl(Context context, String apkPath) {
|
||||||
super(context);
|
super(context, apkPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -167,7 +171,7 @@ abstract class InstallPrivileged {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected String getSystemFolder() {
|
protected String getSystemFolder() {
|
||||||
return "/system/priv-app/FDroid/";
|
return "/system/priv-app/FDroidPrivileged/";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,13 +182,13 @@ abstract class InstallPrivileged {
|
|||||||
List<String> commands = new ArrayList<>(3);
|
List<String> commands = new ArrayList<>(3);
|
||||||
commands.add("mkdir -p " + getSystemFolder()); // create app directory if not existing
|
commands.add("mkdir -p " + getSystemFolder()); // create app directory if not existing
|
||||||
commands.add("chmod 755 " + getSystemFolder());
|
commands.add("chmod 755 " + getSystemFolder());
|
||||||
commands.add("cat " + context.getPackageCodePath() + " > " + getInstallPath() + ".tmp");
|
commands.add("cat " + apkPath + " > " + getInstallPath() + ".tmp");
|
||||||
commands.add("chmod 644 " + getInstallPath() + ".tmp");
|
commands.add("chmod 644 " + getInstallPath() + ".tmp");
|
||||||
return commands;
|
return commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Currently only works with reboot
|
* NOTE: Only works with reboot
|
||||||
* <p/>
|
* <p/>
|
||||||
* File observers on /system/priv-app/ have been removed because they don't work with the new
|
* File observers on /system/priv-app/ have been removed because they don't work with the new
|
||||||
* cluser-style layout. See
|
* cluser-style layout. See
|
||||||
|
@ -41,6 +41,7 @@ import org.fdroid.fdroid.FDroidApp;
|
|||||||
import org.fdroid.fdroid.Preferences;
|
import org.fdroid.fdroid.Preferences;
|
||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
import org.fdroid.fdroid.installer.Installer;
|
import org.fdroid.fdroid.installer.Installer;
|
||||||
|
import org.fdroid.fdroid.installer.PrivilegedInstaller;
|
||||||
|
|
||||||
import eu.chainfire.libsuperuser.Shell;
|
import eu.chainfire.libsuperuser.Shell;
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ public class InstallPrivilegedDialogActivity extends FragmentActivity {
|
|||||||
if (Preferences.get().isFirstTime()) {
|
if (Preferences.get().isFirstTime()) {
|
||||||
Preferences.get().setFirstTime(false);
|
Preferences.get().setFirstTime(false);
|
||||||
|
|
||||||
if (Installer.hasSystemPermissions(context, context.getPackageManager())) {
|
if (PrivilegedInstaller.isAvailable(context)) {
|
||||||
Preferences.get().setSystemInstallerEnabled(true);
|
Preferences.get().setSystemInstallerEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
runFirstTime(context);
|
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
|
// hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay
|
||||||
ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId());
|
ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId());
|
||||||
|
|
||||||
String message = getString(R.string.system_install_first_time_message) + "<br/><br/>" + InstallPrivileged.create(getApplicationContext()).getWarningInfo();
|
String message = getString(R.string.system_install_first_time_message) + "<br/><br/>"
|
||||||
|
+ InstallPrivileged.create(getApplicationContext(), null).getWarningInfo();
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(theme)
|
AlertDialog.Builder builder = new AlertDialog.Builder(theme)
|
||||||
.setMessage(Html.fromHtml(message))
|
.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
|
// hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay
|
||||||
ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId());
|
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
|
// enable system installer on installation success
|
||||||
Preferences.get().setSystemInstallerEnabled(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
|
// hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay
|
||||||
ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId());
|
ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId());
|
||||||
|
|
||||||
final boolean systemApp = Installer.hasSystemPermissions(this, this.getPackageManager());
|
final boolean systemApp = PrivilegedInstaller.isAvailable(this);
|
||||||
|
|
||||||
if (systemApp) {
|
if (systemApp) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(theme)
|
AlertDialog.Builder builder = new AlertDialog.Builder(theme)
|
||||||
|
@ -19,6 +19,7 @@ import org.fdroid.fdroid.Preferences;
|
|||||||
import org.fdroid.fdroid.PreferencesActivity;
|
import org.fdroid.fdroid.PreferencesActivity;
|
||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
import org.fdroid.fdroid.Utils;
|
import org.fdroid.fdroid.Utils;
|
||||||
|
import org.fdroid.fdroid.installer.PrivilegedInstaller;
|
||||||
import org.fdroid.fdroid.privileged.install.InstallPrivilegedDialogActivity;
|
import org.fdroid.fdroid.privileged.install.InstallPrivilegedDialogActivity;
|
||||||
import org.fdroid.fdroid.installer.Installer;
|
import org.fdroid.fdroid.installer.Installer;
|
||||||
|
|
||||||
@ -195,7 +196,7 @@ public class PreferencesFragment extends PreferenceFragment
|
|||||||
final CheckBoxPreference pref = (CheckBoxPreference) preference;
|
final CheckBoxPreference pref = (CheckBoxPreference) preference;
|
||||||
|
|
||||||
if (pref.isChecked()) {
|
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
|
// system-permission are granted, i.e. F-Droid is a system-app
|
||||||
SharedPreferences.Editor editor = pref.getSharedPreferences().edit();
|
SharedPreferences.Editor editor = pref.getSharedPreferences().edit();
|
||||||
editor.putBoolean(Preferences.PREF_SYSTEM_INSTALLER, true);
|
editor.putBoolean(Preferences.PREF_SYSTEM_INSTALLER, true);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user