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_installing">installing…</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_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">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 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_uninstall">Do you want to uninstall F-Droid?</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
|
||||
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()) {
|
||||
|
@ -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
|
||||
|
@ -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<String> getInstallCommands() {
|
||||
final List<String> 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<String> getCopyToSystemCommands() {
|
||||
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");
|
||||
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<String> 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
|
||||
* <p/>
|
||||
* File observers on /system/priv-app/ have been removed because they don't work with the new
|
||||
* cluser-style layout. See
|
||||
|
@ -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) + "<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)
|
||||
.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)
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user