示例#1
0
文件: Util.java 项目: paour/XPrivacy
  public static String hasProLicense(Context context) {
    try {
      // Get license
      String[] license = getProLicenseUnchecked();
      if (license == null) return null;
      String name = license[0];
      String email = license[1];
      String signature = license[2];

      // Get bytes
      byte[] bEmail = email.getBytes("UTF-8");
      byte[] bSignature = hex2bytes(signature);
      if (bEmail.length == 0 || bSignature.length == 0) {
        Util.log(null, Log.ERROR, "Licensing: invalid file");
        return null;
      }

      // Verify license
      boolean licensed = verifyData(bEmail, bSignature, getPublicKey(context));
      if (licensed) Util.log(null, Log.INFO, "Licensing: ok for " + name);
      else Util.log(null, Log.ERROR, "Licensing: invalid for " + name);

      // Return result
      if (licensed) return name;
    } catch (Throwable ex) {
      Util.bug(null, ex);
    }
    return null;
  }
示例#2
0
 @Override
 public boolean onCreate() {
   try {
     String packageName = PrivacyManager.class.getPackage().getName();
     File out =
         new File(
             Environment.getDataDirectory()
                 + File.separator
                 + "data"
                 + File.separator
                 + packageName
                 + File.separator
                 + "meta.xml");
     Util.log(null, Log.INFO, "Writing meta=" + out.getAbsolutePath());
     InputStream is = getContext().getAssets().open("meta.xml");
     OutputStream os = new FileOutputStream(out.getAbsolutePath());
     byte[] buffer = new byte[1024];
     int read;
     while ((read = is.read(buffer)) != -1) os.write(buffer, 0, read);
     is.close();
     os.flush();
     os.close();
     out.setReadable(true, false);
   } catch (Throwable ex) {
     Util.bug(null, ex);
   }
   return true;
 }
示例#3
0
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    if (PrivacyService.checkClient()) {
      // Set theme
      int userId = Util.getUserId(Process.myUid());
      String themeName = PrivacyManager.getSetting(userId, PrivacyManager.cSettingTheme, "");
      mThemeId = (themeName.equals("Dark") ? R.style.CustomTheme : R.style.CustomTheme_Light);
      setTheme(mThemeId);
      super.onCreate(savedInstanceState);
    } else {
      super.onCreate(savedInstanceState);
      // Privacy client now available
      setContentView(R.layout.reboot);

      try {
        PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
        TextView tvVersion = (TextView) findViewById(R.id.tvVersion);
        tvVersion.setText(pInfo.versionName);
      } catch (Throwable ex) {
        Util.bug(null, ex);
      }

      // Show reason
      if (PrivacyService.getClient() == null) {
        TextView tvRebootClient = (TextView) findViewById(R.id.tvRebootClient);
        tvRebootClient.setVisibility(View.VISIBLE);
        Requirements.checkCompatibility(this);
      } else {
        TextView tvRebootClient = (TextView) findViewById(R.id.tvRebootVersion);
        tvRebootClient.setVisibility(View.VISIBLE);
        Requirements.check(this);
      }
    }
  }
示例#4
0
 private boolean isAccountAllowed(String accountName, String accountType, int uid) {
   try {
     String sha1 = Util.sha1(accountName + accountType);
     if (PrivacyManager.getSettingBool(uid, Meta.cTypeAccount, sha1, false, true)) return true;
   } catch (Throwable ex) {
     Util.bug(this, ex);
   }
   return false;
 }
示例#5
0
文件: Util.java 项目: paour/XPrivacy
 public static boolean isProEnablerInstalled(Context context) {
   Version version = getProEnablerVersion(context);
   if (version != null
       && isValidProEnablerVersion(version)
       && hasValidProEnablerSignature(context)) {
     Util.log(null, Log.INFO, "Licensing: enabler installed");
     return true;
   }
   Util.log(null, Log.INFO, "Licensing: enabler not installed");
   return false;
 }
示例#6
0
文件: Util.java 项目: paour/XPrivacy
  public static String[] getProLicenseUnchecked() {
    // Get license file name
    String storageDir = Environment.getExternalStorageDirectory().getAbsolutePath();
    File licenseFile = new File(storageDir + File.separator + LICENSE_FILE_NAME);
    if (!licenseFile.exists())
      licenseFile =
          new File(storageDir + File.separator + ".xprivacy" + File.separator + LICENSE_FILE_NAME);

    // Get imported license file name
    String importedLicense =
        getUserDataDirectory(Process.myUid()) + File.separator + LICENSE_FILE_NAME;

    // Import license file
    if (licenseFile.exists()) {
      try {
        File out = new File(importedLicense);
        Util.log(null, Log.WARN, "Licensing: importing " + out.getAbsolutePath());
        InputStream is = new FileInputStream(licenseFile.getAbsolutePath());
        OutputStream os = new FileOutputStream(out.getAbsolutePath());
        byte[] buffer = new byte[1024];
        int read;
        while ((read = is.read(buffer)) != -1) os.write(buffer, 0, read);
        is.close();
        os.flush();
        os.close();

        // Protect license file
        setPermissions(out.getAbsolutePath(), 0700, Process.myUid(), Process.myUid());

        licenseFile.delete();
      } catch (Throwable ex) {
        Util.bug(null, ex);
      }
    }

    // Check license file
    licenseFile = new File(importedLicense);
    if (licenseFile.exists()) {
      // Read license
      try {
        IniFile iniFile = new IniFile(licenseFile);
        String name = iniFile.get("name", "");
        String email = iniFile.get("email", "");
        String signature = iniFile.get("signature", "");
        return new String[] {name, email, signature};
      } catch (Throwable ex) {
        bug(null, ex);
        return null;
      }
    } else Util.log(null, Log.INFO, "Licensing: no license file");
    return null;
  }
示例#7
0
 @Override
 protected void after(MethodHookParam param) throws Throwable {
   String methodName = param.method.getName();
   if (methodName.equals("getAddress")) {
     if (param.getResult() != null && isRestricted(param))
       param.setResult(PrivacyManager.getDefacedProp("MAC"));
   } else Util.log(this, Log.WARN, "Unknown method=" + methodName);
 }
示例#8
0
  @Override
  public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    if (sUriMatcher.match(uri) == TYPE_RESTRICTION) {
      // Check access
      enforcePermission();

      // Get arguments
      String restrictionName = selection;
      int uid = values.getAsInteger(COL_UID);
      String methodName = values.getAsString(COL_METHOD);
      boolean allowed = !Boolean.parseBoolean(values.getAsString(COL_RESTRICTED));

      // Update
      updateRestriction(uid, restrictionName, methodName, allowed);

      return 1; // rows
    } else if (sUriMatcher.match(uri) == TYPE_USAGE) {
      Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

      // Get arguments
      int uid = values.getAsInteger(COL_UID);
      String restrictionName = values.getAsString(PrivacyProvider.COL_RESTRICTION);
      String methodName = values.getAsString(COL_METHOD);
      boolean restricted = false;
      if (values.containsKey(PrivacyProvider.COL_RESTRICTED))
        restricted = values.getAsBoolean(PrivacyProvider.COL_RESTRICTED);
      long timeStamp = values.getAsLong(PrivacyProvider.COL_USED);
      Util.log(
          null,
          Log.INFO,
          String.format(
              "Update usage data %d/%s/%s=%b", uid, restrictionName, methodName, restricted));

      // Update usage data
      if (methodName != null) updateUsage(uid, restrictionName, methodName, restricted, timeStamp);

      return 1;
    } else if (sUriMatcher.match(uri) == TYPE_SETTING) {
      // Check access
      enforcePermission();

      // Get arguments
      String settingName = selection;

      // Update setting
      SharedPreferences prefs =
          getContext().getSharedPreferences(PREF_SETTINGS, Context.MODE_WORLD_READABLE);
      SharedPreferences.Editor editor = prefs.edit();
      editor.putString(getSettingPref(settingName), values.getAsString(COL_VALUE));
      editor.apply();
      setPrefFileReadable(PREF_SETTINGS);

      return 1;
    }

    throw new IllegalArgumentException(uri.toString());
  }
示例#9
0
文件: Util.java 项目: paour/XPrivacy
 public static String getSelfVersionName(Context context) {
   try {
     String self = Util.class.getPackage().getName();
     PackageManager pm = context.getPackageManager();
     PackageInfo pInfo = pm.getPackageInfo(self, 0);
     return pInfo.versionName;
   } catch (NameNotFoundException ex) {
     Util.bug(null, ex);
     return null;
   }
 }
示例#10
0
文件: Util.java 项目: paour/XPrivacy
 @SuppressLint("NewApi")
 public static int getAppId(int uid) {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
     try {
       // UserHandle: public static final int getAppId(int uid)
       Method method = (Method) UserHandle.class.getDeclaredMethod("getAppId", int.class);
       uid = (Integer) method.invoke(null, uid);
     } catch (Throwable ex) {
       Util.bug(null, ex);
     }
   return uid;
 }
示例#11
0
文件: Util.java 项目: paour/XPrivacy
 public static Version getProEnablerVersion(Context context) {
   try {
     String proPackageName = context.getPackageName() + ".pro";
     PackageManager pm = context.getPackageManager();
     PackageInfo pi = pm.getPackageInfo(proPackageName, 0);
     return new Version(pi.versionName);
   } catch (NameNotFoundException ignored) {
   } catch (Throwable ex) {
     Util.bug(null, ex);
   }
   return null;
 }
示例#12
0
 @Override
 protected void before(MethodHookParam param) throws Throwable {
   if (mMethod == Methods.addGeofences || mMethod == Methods.removeGeofences) {
     if (isRestricted(param)) param.setResult(null);
   } else if (mMethod == Methods.getLastLocation) {
     // Do nothing
   } else if (mMethod == Methods.removeLocationUpdates) {
     if (isRestricted(param)) removeLocationListener(param);
   } else if (mMethod == Methods.requestLocationUpdates) {
     if (isRestricted(param)) replaceLocationListener(param);
   } else Util.log(this, Log.WARN, "Unknown method=" + param.method.getName());
 }
示例#13
0
文件: Util.java 项目: paour/XPrivacy
 public static void setPermissions(String path, int mode, int uid, int gid) {
   try {
     // frameworks/base/core/java/android/os/FileUtils.java
     Class<?> fileUtils = Class.forName("android.os.FileUtils");
     Method setPermissions =
         fileUtils.getMethod("setPermissions", String.class, int.class, int.class, int.class);
     setPermissions.invoke(null, path, mode, uid, gid);
     Util.log(
         null,
         Log.WARN,
         "Changed permission path="
             + path
             + " mode="
             + Integer.toOctalString(mode)
             + " uid="
             + uid
             + " gid="
             + gid);
   } catch (Throwable ex) {
     Util.bug(null, ex);
   }
 }
示例#14
0
文件: Util.java 项目: paour/XPrivacy
 public static boolean hasLBE() {
   if (!mHasLBEDetermined) {
     mHasLBEDetermined = true;
     try {
       File apps = new File(Environment.getDataDirectory() + File.separator + "app");
       File[] files = (apps == null ? null : apps.listFiles());
       if (files != null)
         for (File file : files) if (file.getName().startsWith("com.lbe.security")) mHasLBE = true;
     } catch (Throwable ex) {
       Util.bug(null, ex);
     }
   }
   return mHasLBE;
 }
示例#15
0
 @Override
 protected void after(MethodHookParam param) throws Throwable {
   if (mMethod == Methods.addGeofences || mMethod == Methods.removeGeofences) {
     // Do nothing
   } else if (mMethod == Methods.getLastLocation) {
     Location location = (Location) param.getResult();
     if (location != null && isRestricted(param))
       param.setResult(PrivacyManager.getDefacedLocation(Binder.getCallingUid(), location));
   } else if (mMethod == Methods.removeLocationUpdates) {
     // Do nothing
   } else if (mMethod == Methods.requestLocationUpdates) {
     // Do nothing
   } else Util.log(this, Log.WARN, "Unknown method=" + param.method.getName());
 }
示例#16
0
  @Override
  protected void after(MethodHookParam param) throws Throwable {
    if (mMethod != Methods.addGeofence
        && mMethod != Methods.addNmeaListener
        && mMethod != Methods.addProximityAlert
        && mMethod != Methods.removeUpdates
        && mMethod != Methods.requestLocationUpdates
        && mMethod != Methods.requestSingleUpdate)
      if (mMethod == Methods.isProviderEnabled) {
        if (isRestricted(param)) param.setResult(false);

      } else if (mMethod == Methods.getGpsStatus) {
        if (param.getResult() != null && isRestricted(param)) {
          GpsStatus status = (GpsStatus) param.getResult();
          // private GpsSatellite mSatellites[]
          try {
            Field mSatellites = status.getClass().getDeclaredField("mSatellites");
            mSatellites.setAccessible(true);
            mSatellites.set(status, new GpsSatellite[0]);
          } catch (Throwable ex) {
            Util.bug(null, ex);
          }
        }
      } else if (mMethod == Methods.getLastLocation || mMethod == Methods.getLastKnownLocation) {
        Location location = (Location) param.getResult();
        if (location != null && isRestricted(param))
          param.setResult(PrivacyManager.getDefacedLocation(Binder.getCallingUid(), location));

      } else if (mMethod == Methods.getProviders) {
        if (param.getResult() != null && isRestricted(param))
          param.setResult(new ArrayList<String>());

      } else if (mMethod == Methods.sendExtraCommand) {
        if (isRestricted(param)) param.setResult(false);

      } else Util.log(this, Log.WARN, "Unknown method=" + param.method.getName());
  }
示例#17
0
 private void removeLocationListener(MethodHookParam param) {
   if (param.args.length >= 1
       && param.args[0] != null
       && LocationListener.class.isAssignableFrom(param.args[0].getClass())) {
     LocationListener listener = (LocationListener) param.args[0];
     synchronized (mListener) {
       XLocationListener xlistener = mListener.get(listener);
       if (xlistener == null) Util.log(this, Log.WARN, "Not found count=" + mListener.size());
       else {
         param.args[0] = xlistener;
         mListener.remove(listener);
       }
     }
   } else param.setResult(null);
 }
示例#18
0
  @Override
  public int delete(Uri uri, String where, String[] selectionArgs) {
    // Check access
    enforcePermission();

    if (sUriMatcher.match(uri) == TYPE_RESTRICTION) {
      int rows = 0;

      // Get argument
      int uid = Integer.parseInt(selectionArgs[0]);

      // Method restrictions
      SharedPreferences prefs =
          getContext().getSharedPreferences(PREF_RESTRICTION, Context.MODE_WORLD_READABLE);
      SharedPreferences.Editor editor = prefs.edit();
      for (String restrictionName : PrivacyManager.getRestrictions(true)) {
        for (PrivacyManager.MethodDescription md : PrivacyManager.getMethods(restrictionName)) {
          rows++;
          editor.remove(getExceptionPref(uid, restrictionName, md.getMethodName()));
        }
      }
      editor.apply();
      setPrefFileReadable(PREF_RESTRICTION);

      // Group restrictions
      for (String restrictionName : PrivacyManager.getRestrictions(true)) {
        rows++;
        updateRestriction(uid, restrictionName, null, true);
      }

      return rows;
    } else if (sUriMatcher.match(uri) == TYPE_SETTING && selectionArgs == null) {
      int rows = 0;
      SharedPreferences prefs =
          getContext().getSharedPreferences(PREF_SETTINGS, Context.MODE_WORLD_READABLE);
      SharedPreferences.Editor editor = prefs.edit();
      for (String pref : prefs.getAll().keySet()) {
        rows++;
        editor.remove(pref);
        Util.log(null, Log.INFO, "Removed setting=" + pref);
      }
      editor.apply();
      setPrefFileReadable(PREF_SETTINGS);
      return rows;
    }

    throw new IllegalArgumentException(uri.toString());
  }
示例#19
0
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.app, menu);

    // Launch
    PackageManager pm = getPackageManager();
    if (pm.getLaunchIntentForPackage(mAppInfo.getPackageName()) == null)
      menu.findItem(R.id.menu_app_launch).setEnabled(false);

    // Play
    boolean hasMarketLink = Util.hasMarketLink(this, mAppInfo.getPackageName());
    menu.findItem(R.id.menu_app_store).setEnabled(hasMarketLink);

    return true;
  }
示例#20
0
 private void replaceLocationListener(MethodHookParam param) throws Throwable {
   if (param.args.length >= 2
       && param.args[1] != null
       && LocationListener.class.isAssignableFrom(param.args[1].getClass())) {
     if (!(param.args[1] instanceof XLocationListener)) {
       LocationListener listener = (LocationListener) param.args[1];
       if (listener != null) {
         XLocationListener xListener = new XLocationListener(listener);
         synchronized (mListener) {
           mListener.put(listener, xListener);
           Util.log(this, Log.INFO, "Added count=" + mListener.size());
         }
         param.args[1] = xListener;
       }
     }
   } else param.setResult(null);
 }
示例#21
0
 private void replaceLocationListener(MethodHookParam param, int arg) throws Throwable {
   if (param.args.length > arg
       && param.args[arg] != null
       && LocationListener.class.isAssignableFrom(param.args[arg].getClass())) {
     if (!(param.args[arg] instanceof XLocationListener)) {
       LocationListener listener = (LocationListener) param.args[arg];
       if (listener != null) {
         XLocationListener xListener = new XLocationListener(listener);
         synchronized (mListener) {
           mListener.put(listener, xListener);
           Util.log(
               this,
               Log.INFO,
               "Added count=" + mListener.size() + " uid=" + Binder.getCallingUid());
         }
         param.args[arg] = xListener;
       }
     }
   } else
     // Intent
     param.setResult(null);
 }
示例#22
0
  @Override
  protected void before(MethodHookParam param) throws Throwable {
    if (mMethod == Methods.exec) {
      // Get programs
      String[] progs = null;
      if (param.args.length > 0 && param.args[0] != null)
        if (String.class.isAssignableFrom(param.args[0].getClass()))
          progs = new String[] {(String) param.args[0]};
        else progs = (String[]) param.args[0];

      // Check programs
      if (progs != null) {
        String command = TextUtils.join(" ", progs);
        if ((mCommand == null && !command.contains("sh ") && !command.contains("su "))
            || (mCommand != null && command.contains(mCommand + " ")))
          if (isRestricted(param, mCommand == null ? getMethodName() : mCommand))
            param.setThrowable(new IOException());
      }
    } else if (mMethod == Methods.load || mMethod == Methods.loadLibrary) {
      // Skip pre Android
      if (Process.myUid() != 0)
        if (isRestricted(param)) param.setResult(new UnsatisfiedLinkError());
    } else Util.log(this, Log.WARN, "Unknown method=" + param.method.getName());
  }
示例#23
0
 @Override
 protected void before(MethodHookParam param) throws Throwable {
   if (mMethod == Methods.getNfcAdapter) {
     if (isRestricted(param)) param.setResult(null);
   } else Util.log(this, Log.WARN, "Unknown method=" + param.method.getName());
 }
示例#24
0
  @Override
  @SuppressWarnings("unchecked")
  protected void after(XParam param) throws Throwable {
    if (mMethod != Methods.addOnAccountsUpdatedListener
        && mMethod != Methods.removeOnAccountsUpdatedListener) {
      int uid = Binder.getCallingUid();
      if (mMethod == Methods.blockingGetAuthToken) {
        if (param.args.length > 0 && param.args[0] != null) {
          Account account = (Account) param.args[0];
          if (param.getResult() != null
              && isRestrictedExtra(param, account == null ? null : account.name))
            if (!isAccountAllowed(account, uid)) param.setResult(null);
        }

      } else if (mMethod == Methods.getAccounts) {
        if (param.getResult() != null && isRestricted(param)) {
          Account[] accounts = (Account[]) param.getResult();
          param.setResult(filterAccounts(accounts, uid));
        }

      } else if (mMethod == Methods.getAccountsByType
          || mMethod == Methods.getAccountsByTypeForPackage) {
        if (param.args.length > 0)
          if (param.getResult() != null && isRestrictedExtra(param, (String) param.args[0])) {
            Account[] accounts = (Account[]) param.getResult();
            param.setResult(filterAccounts(accounts, uid));
          }

      } else if (mMethod == Methods.getAccountsByTypeAndFeatures) {
        if (param.args.length > 0)
          if (param.getResult() != null && isRestrictedExtra(param, (String) param.args[0])) {
            AccountManagerFuture<Account[]> future =
                (AccountManagerFuture<Account[]>) param.getResult();
            param.setResult(new XFutureAccount(future, uid));
          }

      } else if (mMethod == Methods.getAuthenticatorTypes) {
        if (param.getResult() != null && isRestricted(param))
          param.setResult(new AuthenticatorDescription[0]);

      } else if (mMethod == Methods.getAuthToken) {
        if (param.args.length > 0) {
          Account account = (Account) param.args[0];
          if (param.getResult() != null
              && isRestrictedExtra(param, account == null ? null : account.name)) {
            AccountManagerFuture<Bundle> future = (AccountManagerFuture<Bundle>) param.getResult();
            param.setResult(new XFutureBundle(future, uid));
          }
        }

      } else if (mMethod == Methods.getAuthTokenByFeatures) {
        if (param.getResult() != null && isRestricted(param, (String) param.args[0])) {
          AccountManagerFuture<Bundle> future = (AccountManagerFuture<Bundle>) param.getResult();
          param.setResult(new XFutureBundle(future, uid));
        }

      } else if (mMethod == Methods.hasFeatures) {
        if (param.args.length > 0 && param.args[0] != null) {
          Account account = (Account) param.args[0];
          if (param.getResult() != null
              && isRestrictedExtra(param, account == null ? null : account.name))
            if (!isAccountAllowed(account, uid)) param.setResult(new XFutureBoolean());
        }

      } else Util.log(this, Log.WARN, "Unknown method=" + param.method.getName());
    }
  }
示例#25
0
  @Override
  @SuppressWarnings("unchecked")
  protected void before(XParam param) throws Throwable {
    if (mMethod == Methods.addOnAccountsUpdatedListener) {
      if (param.args.length > 0 && param.args[0] != null)
        if (isRestricted(param)) {
          int uid = Binder.getCallingUid();
          OnAccountsUpdateListener listener = (OnAccountsUpdateListener) param.args[0];
          XOnAccountsUpdateListener xListener;
          synchronized (mListener) {
            xListener = mListener.get(listener);
            if (xListener == null) {
              xListener = new XOnAccountsUpdateListener(listener, uid);
              mListener.put(listener, xListener);
              Util.log(this, Log.WARN, "Added count=" + mListener.size() + " uid=" + uid);
            }
          }
          param.args[0] = xListener;
        }

    } else if (mMethod == Methods.removeOnAccountsUpdatedListener) {
      if (param.args.length > 0 && param.args[0] != null)
        synchronized (mListener) {
          OnAccountsUpdateListener listener = (OnAccountsUpdateListener) param.args[0];
          XOnAccountsUpdateListener xListener = mListener.get(listener);
          if (xListener != null) {
            param.args[0] = xListener;
            Util.log(
                this,
                Log.WARN,
                "Removed count=" + mListener.size() + " uid=" + Binder.getCallingUid());
          }
        }

    } else if (mMethod == Methods.getAccountsByTypeAndFeatures) {
      if (param.args.length > 2 && param.args[2] != null)
        if (isRestrictedExtra(param, (String) param.args[0])) {
          AccountManagerCallback<Account[]> callback =
              (AccountManagerCallback<Account[]>) param.args[2];
          param.args[2] = new XAccountManagerCallbackAccount(callback, Binder.getCallingUid());
        }

    } else if (mMethod == Methods.getAuthToken) {
      if (param.args.length > 0) {
        Account account = (Account) param.args[0];
        for (int i = 0; i < param.args.length; i++)
          if (param.args[i] instanceof AccountManagerCallback<?>)
            if (isRestricted(param, account == null ? null : account.name)) {
              AccountManagerCallback<Bundle> callback =
                  (AccountManagerCallback<Bundle>) param.args[i];
              param.args[i] = new XAccountManagerCallbackBundle(callback, Binder.getCallingUid());
            }
      }

    } else if (mMethod == Methods.getAuthTokenByFeatures) {
      if (param.args.length > 0)
        for (int i = 0; i < param.args.length; i++)
          if (param.args[i] instanceof AccountManagerCallback<?>)
            if (isRestricted(param, (String) param.args[0])) {
              AccountManagerCallback<Bundle> callback =
                  (AccountManagerCallback<Bundle>) param.args[i];
              param.args[i] = new XAccountManagerCallbackBundle(callback, Binder.getCallingUid());
            }

    } else if (mMethod == Methods.hasFeatures) {
      if (param.args.length > 0) {
        Account account = (Account) param.args[0];
        for (int i = 0; i < param.args.length; i++)
          if (param.args[i] instanceof AccountManagerCallback<?>)
            if (isRestricted(param, account == null ? null : account.name)) {
              AccountManagerCallback<Boolean> callback =
                  (AccountManagerCallback<Boolean>) param.args[i];
              param.args[i] = new XAccountManagerCallbackBoolean(callback);
            }
      }
    }
  }