Privates exposed

We’re all tempted, right… But don’t do it. Just don’t.

Access modifiers, as we all know, are fundamental part of object oriented languages. When used correctly, they help to provide clear interfaces for classes by data encapsulation and allow carefree development of software using various APIs. When you see a private (or protected) method, you think there’s a good reason why the one who implemented the class decided to do so. If for some reason you do need to go further than the public API allows you to, you usually find a valid workaround – and even then you question if there is a better way to achieve what you are trying to accomplish.

However, in some extremely rare cases you might find yourself in a situation where there is no workaround and without access to some protected/private method you are facing a wall. Or the possible workaround costs you hours or even weeks more work when with the access you could be done in just few minutes. What to do? Well, it’s up to you, but if you really want to take the easy (but risky) path, you can, since there really are no such things as protected or private. An access modifier is more than a recommendation though and you should think not twice but N times before dismissing one.

You have been warned

Accessing private bits in C++ is a bit tricky. The method I’d recommend is to get the address of, i.e. pointer to the function in question. You might need to calculate the offset from e.g. the class pointer, but this can be done by ye olde trial-and-error method. You may also consider trying #ifdef hacks, but those could drive you crazy with all the other errors they might cause.

In other languages, namely those that support the magicks of reflection (Java and C# for instance), things can be far more simple. For example, in (Android) Java you access and invoke a private method as follows:

Method method = SomeClass.class.getDeclaredMethod("methodName");
method.setAccessible(true);
SomeClass someClass = new SomeClass();
method.invoke(someClass);

The constructors and members are accessible in a similar fashion. See Class and Method classes for more information.

Note that  even though your code accessing and invoking private methods works now, you cannot rely it to work in the future. If – and often times when – the code you’re referencing and the private method signature changes, your code will throw a NoSuchMethodException. Therefore, it’s a no-brainer to surround the code with try-catch. But what then? What do you do when an exception is thrown and you’ve caught it. Albeit this is from programming 101, I’m gonna say it: Handle the exception gracefully; Your application has to perform even when your hack of access violation trickery doesn’t! Same goes regardless of what your weapon (language) of choice is.

I warned you

 

Case Android Bluetooth socket

I was working on a cross-platform peer web project called Thali. Furthermore, I was in charge of the native Android layer of the project (see Thali Android Connector Library). We had had issues (in addition to number of other problems) with failing Bluetooth sockets, namely in the connection process.

We noticed that many reported better results using a workaround that they used to create a socket with a specified port. One uses BluetoothDevice class to construct BluetoothSocket instances. However, using the publicly available methods (read: the methods intended to be used) to create sockets one cannot define the port – instead the port is decided for you. If you really want to define the port yourself, there is a way: Use reflection to invoke the method with which you can define the port. And it’s not even protected/private, just cannot be called directly:

// bluetoothDevice is an instance of BluetoothDevice class
Method method = bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
BluetoothSocket bluetoothSocket = (BluetoothSocket) method.invoke(bluetoothDevice, 1); // 1 is the port number

This solution didn’t work for us since Thali project uses insecure RFCOMM sockets vs. the secure ones and the method for constructing insecure sockets with a specified port number is neither public nor available. Thus, to accomplish the same effect as the aforementioned code snippet, one has to access the private constructor of the BluetoothSocket class. So I created a helper method which allows you to construct both secure and insecure BluetoothSocket instances with the desired channel/port (see BluetoothUtils class in Thali Android Connectivity Library project):

public static BluetoothSocket createBluetoothSocketToServiceRecord(
        BluetoothDevice bluetoothDevice, UUID serviceRecordUuid, int channelOrPort, boolean secure) {
    Constructor[] bluetoothSocketConstructors = BluetoothSocket.class.getDeclaredConstructors();
    Constructor bluetoothSocketConstructor = null;

    for (Constructor constructor : bluetoothSocketConstructors) {
        Class<?>[] parameterTypes = constructor.getParameterTypes();
        boolean takesBluetoothDevice = false;
        boolean takesParcelUuid = false;

        for (Class<?> parameterType : parameterTypes) {
            if (parameterType.equals(BluetoothDevice.class)) {
                takesBluetoothDevice = true;
            } else if (parameterType.equals(ParcelUuid.class)) {
                takesParcelUuid = true;
            }
        }

        if (takesBluetoothDevice && takesParcelUuid) {
            // We found the right constructor
            bluetoothSocketConstructor = constructor;
            break;
        }
    }

    // This is the constructor we should now have:
    // BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, BluetoothDevice device,
    //      int port, ParcelUuid uuid) throws IOException

    // Create the parameters for the constructor
    Object[] parameters = new Object[] {
            Integer.valueOf(1), // BluetoothSocket.TYPE_RFCOMM
            Integer.valueOf(-1),
            Boolean.valueOf(secure),
            Boolean.valueOf(secure),
            bluetoothDevice,
            Integer.valueOf(channelOrPort),
            new ParcelUuid(serviceRecordUuid)
    };

    bluetoothSocketConstructor.setAccessible(true);
    BluetoothSocket bluetoothSocket = null;

    try {
        bluetoothSocket = (BluetoothSocket)bluetoothSocketConstructor.newInstance(parameters);
        Log.d(TAG, "createBluetoothSocketToServiceRecord: Socket created with channel/port " + channelOrPort);
    } catch (Exception e) {
        Log.e(TAG, "createBluetoothSocketToServiceRecord: Failed to create a new Bluetooth socket instance: " + e.getMessage(), e);
    }

    return bluetoothSocket;
}

What good did it do?

None. Jacksh*t! It did no good at all as far as I can tell.

“Paskaaks se mitään teki.”

The hack didn’t solve our problems. Turns out the problem was elsewhere and fault of my own (I’ll let you in on a secret, if you haven’t realized it by now: I’m not a guru. I’m not a master programmer. I’m your average software developer and, if anything, I’m lazy enough to find quick, clean solutions to problems that usually work.) That said, the hack might have provided useful on earlier versions of Android, but the possible platform issue was most likely fixed on Lollipop and newer. With the hack the Bluetooth socket worked as well as without the trickery and when it was bound to fail it did so regardless.

So as final words I give you…

Reasons why NOT to access protected/private stuff

  1. 99.9 times out of 100, there’s really no need – work around it!
  2. Given that whoever wrote the code is not a complete tool, made it inaccessible for a reason.
  3. Your hack won’t most probably be sustainable. It will break. Just see. Unless, of course, no one will eveeeeer touch the code you’re referencing.
  4. As per the aforementioned – you have to keep maintaining your code constantly to make sure it stays up-to-date with the code you are referencing.
  5. You’re just asking for trouble.
  6. Go to 1.
Run away
The recommended action

(Universal Windows apps)^2

The great majority of apps built for Windows 8.1/Windows Phone 8.1 work on Windows 10 as-is – no changes required what so ever. But what if you want to leverage the new APIs provided by Windows 10 such as the inking API while still supporting the Windows 8.1 version of your app? Or you might be among the few unfortunate ones who have been using some API deprecated on Windows 10; UserInformation class no longer works on Windows 10 but you have to use the User class instead. How to do that without duplicating the code base and having two completely separate app projects to maintain? In this article I’ll describe two approaches to do that.

Shared code and assets in portable project

The first approach is to include all the shared code (in practice that can be almost all of your code) to a separate portable project in your Windows 8.1 solution. First you need to create the project: Right click your solution in the solution explorer, hover on Add and select New Project…

Adding a new project to a solution

Use Class Library as the project type, name it and hit OK.

Creating a class library project

Drag all the code and asset files you want to share between both the Windows 8.1 and Windows 10 app to the newly created Class Library project.

Note that if you have a solution that supports both Windows 8.1 and Windows Phone 8.1, you have to have at least a partial main page (the page you navigate to in the start-up) in the original Windows 8.1 and Windows Phone 8.1 projects. This due to the fact that you can’t add a reference to your Class Library project in the Shared (Windows 8.1/Windows Phone 8.1) project where your App class lives. And without the reference you can’t make your app to navigate to a page defined in your Class Library project in the start-up. Makes sense? Ok, cool, let’s carry on…

Now that we have the code moved to the Class Library project, we must add it as a reference to the other projects so that we can access the classes and assets. Right click the References under the projects in the solution explorer and select Add Reference…

Adding references to a project

On Projects tab you should now find the Class Library project. Check the checkbox and click OK.

Adding a project in the solution to another as a reference

Now fix any minor problems you may have and once your app builds and runs it is time to move on to work on the Windows 10 solution. Create a new Universal Windows 10 application project and add the Class Library project containing the shared code to the Windows 10 solution as an existing project:

Adding an existing project to a solution

Add the Class Library project as a reference to your main Windows 10 project (as explained before), make your main project to use the shared code and you’re all set! Fine – I realize it’s not often this simple and you need to do some tweaking to get all the other dependencies working and so on, but these are the first steps to take.

If you now want to extend the app on Windows 10 by utilizing the cool new APIs, you need to add that specific code to the main project. You can’t, of course, access the code in the main project from the shared code (for many reasons, one being that this would create a circular dependency), but one solution is to define interfaces in the shared code and providing the implementations from the main project. See my example, namely IUserInformationHelper interface in the Class Library, Windows 10 UserInformationHelper implementation and App.xaml.cs where the implementation is provided.

Pros

  • Allows management of the shared code as a single project

Cons

  • Other dependencies (Nuget packages and such) may cause problems e.g. if they aren’t as universal and work only on Windows 8.1 and not on Windows 10
  • You cannot use conditional preprocessing blocks in the shared code (#if) to target a specific platform since the compilation symbols are also shared
Conditional compilation symbols in project preferences (WINDOWS_UWP is for Windows 10 apps)

Shared code and asset files as links

Another way of sharing code between solutions is adding the code and asset files as links. Using links you don’t have to change your existing solution. Simply create a new – in this case – Windows 10 application project and start adding the files from your existing Windows 8.1 solution. Right click your new project in the solution explorer, hover on Add and select Existing Item… Then browse the Windows 8.1 solution folder containing the files you want to add, select the files and click Add As Link:

Adding files as links

The files are now shown in your solution explorer. However, they are not physically in your new project but exist in the Windows 8.1 application project folder. Any changes you make to these files will also appear in both projects.

While adding the files individually can be tedious, the benefit here is that you can take advantage of conditional preprocessing blocks in C# code:

#if WINDOWS_UWP
    // Have your Windows 10 specific code here
#else
    // Have your Windows 8.1 specific code here
#endif

Pros

  • Conditional preprocessing blocks and compilation symbols can be used
  • Dependencies to additional libraries and Nuget packages are easier to maintain
  • Adding platform specific features, e.g. new Windows 10 APIs, is trivial

Cons

  • Adding/removing shared code and asset files needs to be done in both solutions separately

Sample code

An example for using the both approaches featured in this article can be found here in GitHub.