Search code examples
c#androidxamarinxamarin.androidapk

Xamarin.Android PackageInstaller Session.commit "Files still open" Exception on apk silent install


I'm trying to code a proof of concept, with Xamarin android. A sort of EMM tool, i.e. an application which will be in charge of installing other applications and managing the device. So Android Marshmallow is a good place to start with android for work features.

My app is a Device Owner, therefore it should have no problem silently installing other applications. It can download an apk from a website without any problem. But when I try to install it, it throws a "Files still open" exception despite calling all Close() methods.

I have taken my code from the excellent android-testdpc github example here.

I have changed it to work in C# with Xamarin.

Here is my code:

    public static bool InstallPackage(Context context, Handler handler, InputStream input, String packageName)
    {
        try
        {
            PackageInstaller packageInstaller = context.PackageManager.PackageInstaller;
            PackageInstaller.SessionParams param = new PackageInstaller.SessionParams(PackageInstallMode.FullInstall);
            param.SetAppPackageName(packageName);
            // set params
            int sessionId = packageInstaller.CreateSession(param);
            PackageInstaller.Session session = packageInstaller.OpenSession(sessionId);
            using (System.IO.Stream output = session.OpenWrite("COSU", 0, -1))
            {
                byte[] buffer = new byte[65536];
                int c;
                while ((c = input.Read(buffer)) != -1)
                {
                    output.Write(buffer, 0, c);
                }
                session.Fsync(output);
                input.Close();
                output.Close();
            }
            session.Commit(createIntentSender(context, sessionId)); // this line throws exception 'Files stil open'
            return true;
        }
        catch (Exception ex)
        {
            Log.Error(TAG, "Error installing package: " + packageName, ex);
            handler.SendMessage(handler.ObtainMessage(Common.MSG_INSTALL_FAIL,
                    packageName));
            return false;
        }
    }

I'm stuck with this for the moment. If I have the time, I will try to install Android Studio and test my code in Java to see if the problem comes from Xamarin.

If someone has any clue for my problem, I will greatly appreciate the help.


Solution

  • SecurityException : if streams opened through openWrite(String, long, long) are still open.

    The Java peer object is not closed yet, this is how I force it for the PackageInstaller.Session.Commit:

    var input = Assets.Open(packageName);
    var packageInstaller = PackageManager.PackageInstaller;
    var sessionParams = new PackageInstaller.SessionParams(PackageInstallMode.FullInstall);
    sessionParams.SetAppPackageName(packageName);
    int sessionId = packageInstaller.CreateSession(sessionParams);
    var session = packageInstaller.OpenSession(sessionId);
    using (var output = session.OpenWrite(packageName, 0, -1))
    {
        input.CopyTo(output);
        session.Fsync(output);
        foreach (var name in session.GetNames())
            Log.Debug("Installer", name);
        output.Close();
        output.Dispose();
        input.Close();
        input.Dispose();
        GC.Collect();
    }
    var pendingIntent = PendingIntent.GetBroadcast(BaseContext, sessionId, new Intent(Intent.ActionInstallPackage), 0);
    session.Commit(pendingIntent.IntentSender);