Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bad Process.StartTime in .NET 6 on Android #67583

Closed
AigioL opened this issue Apr 5, 2022 · 11 comments · Fixed by #67589
Closed

Bad Process.StartTime in .NET 6 on Android #67583

AigioL opened this issue Apr 5, 2022 · 11 comments · Fixed by #67589

Comments

@AigioL
Copy link

AigioL commented Apr 5, 2022

Description

System.Diagnostics.Process.StartTime throws an exception on net6.0-android, but works fine on Xamarin.Android

Reproduction Steps

https://github.com/BeyondDimension/AspNetCore.Mobile/blob/refs/tags/test-process-starttime/src/AspNetCore.Mobile.Droid/MainActivity.cs#L50-L63

void TestProcessStartTime()
{
    string startTimeString;
    try
    {
        var p = global::System.Diagnostics.Process.GetCurrentProcess();
        startTimeString = p.StartTime.ToString();
    }
    catch (Exception e)
    {
        startTimeString = e.ToString();
    }
    WriteLine($"StartTime: {startTimeString}");
}

Expected behavior

Returns the correct DateTime

Screenshot_1649162413

Actual behavior

 android.runtime.JavaProxyThrowable: System.UnauthorizedAccessException: Access to the path '/proc/stat' is denied.
     ---> System.IO.IOException: Permission denied
       --- End of inner exception stack trace ---
        at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
        at Interop.CheckIo(Error error, String path, Boolean isDirectory, Func`2 errorRewriter)
        at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
        at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
        at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
        at System.IO.Strategies.UnixFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
        at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
        at System.IO.Strategies.FileStreamHelpers.ChooseStrategy(FileStream fileStream, String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
        at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
        at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
        at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean useAsync)
        at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize)
        at System.IO.StreamReader.ValidateArgsAndOpenPath(String path, Encoding encoding, Int32 bufferSize)
        at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize)
        at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks)
        at System.IO.File.InternalReadAllText(String path, Encoding encoding)
        at System.IO.File.ReadAllText(String path)
        at System.Diagnostics.Process.get_BootTime()
        at System.Diagnostics.Process.BootTimeToDateTime(TimeSpan timespanAfterBoot)
        at System.Diagnostics.Process.get_StartTimeCore()
        at System.Diagnostics.Process.get_StartTime()

Screenshot_1649162406

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

This is the compiled apk files

Xamarin.Android 12 APK

NET 6.0 APK

@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged New issue has not been triaged by the area owner label Apr 5, 2022
@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@ghost
Copy link

ghost commented Apr 5, 2022

Tagging subscribers to this area: @dotnet/area-system-diagnostics-process
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

System.Diagnostics.Process.StartTime throws an exception on net6.0-android, but works fine on Xamarin.Android

Reproduction Steps

https://github.com/BeyondDimension/AspNetCore.Mobile/blob/refs/tags/test-process-starttime/src/AspNetCore.Mobile.Droid/MainActivity.cs#L50-L63

void TestProcessStartTime()
{
    string startTimeString;
    try
    {
        var p = global::System.Diagnostics.Process.GetCurrentProcess();
        startTimeString = p.StartTime.ToString();
    }
    catch (Exception e)
    {
        startTimeString = e.ToString();
    }
    WriteLine($"StartTime: {startTimeString}");
}

Expected behavior

Returns the correct DateTime

Screenshot_1649162413

Actual behavior

 android.runtime.JavaProxyThrowable: System.UnauthorizedAccessException: Access to the path '/proc/stat' is denied.
     ---> System.IO.IOException: Permission denied
       --- End of inner exception stack trace ---
        at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
        at Interop.CheckIo(Error error, String path, Boolean isDirectory, Func`2 errorRewriter)
        at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
        at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
        at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
        at System.IO.Strategies.UnixFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
        at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
        at System.IO.Strategies.FileStreamHelpers.ChooseStrategy(FileStream fileStream, String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
        at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
        at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
        at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean useAsync)
        at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize)
        at System.IO.StreamReader.ValidateArgsAndOpenPath(String path, Encoding encoding, Int32 bufferSize)
        at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize)
        at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks)
        at System.IO.File.InternalReadAllText(String path, Encoding encoding)
        at System.IO.File.ReadAllText(String path)
        at System.Diagnostics.Process.get_BootTime()
        at System.Diagnostics.Process.BootTimeToDateTime(TimeSpan timespanAfterBoot)
        at System.Diagnostics.Process.get_StartTimeCore()
        at System.Diagnostics.Process.get_StartTime()

Screenshot_1649162406

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

This is the compiled apk files

Xamarin.Android 12 APK

NET 6.0 APK

Author: AigioL
Assignees: -
Labels:

area-System.Diagnostics.Process, os-android, untriaged

Milestone: -

@am11 am11 removed the untriaged New issue has not been triaged by the area owner label Apr 5, 2022
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Apr 5, 2022
@ghost ghost added in-pr There is an active PR which will close this issue when it is merged and removed in-pr There is an active PR which will close this issue when it is merged labels Apr 11, 2022
@steveisok
Copy link
Member

@am11 Do you think you'll have time to fix this?

@am11
Copy link
Member

am11 commented Jul 19, 2022

@steveisok, thanks for the ping. #67589 needs device testing on Android. I tried to setup an emulator last month, but it was having some issues and I got distracted by other stuff. Is there any readymade docker or emulator setup available which I can pull and use without spending time on environment setup?

Otherwise, if someone has the dev device and spare cycles to help, we need to debug this (standalone) C code and compare with Linux desktop to find out which API behaves differently on Android, and what is the minimal change that could be applied to it to get the ball rolling:

#include <assert.h>
#include <stdio.h>
#include <time.h>
#include <inttypes.h>

#define TARGET_LINUX

enum
{
    MicroSecondsToNanoSeconds = 1000,   // 10^3
    SecondsToNanoSeconds = 1000000000,  // 10^9
    SecondsToTicks = 10000000,          // 10^7
    TicksToNanoSeconds = 100,           // 10^2
};

int64_t SystemNative_GetBootTimeTicks()
{
#ifdef TARGET_LINUX
    struct timespec ts;

    int result = clock_gettime(CLOCK_BOOTTIME, &ts);
    assert(result == 0); // only possible errors are if the given clockId isn't supported or &ts is an invalid address
    (void)result; // suppress unused parameter warning in release builds

    int64_t sinceBootTicks = (ts.tv_sec * SecondsToTicks) + (ts.tv_nsec / TicksToNanoSeconds);

    result = clock_gettime(CLOCK_REALTIME_COARSE, &ts);
    assert(result == 0);

    int64_t sinceEpochTicks = (ts.tv_sec * SecondsToTicks) + (ts.tv_nsec / TicksToNanoSeconds);

    return sinceEpochTicks - sinceBootTicks;
#else
    return -1;
#endif
}


int main() {
    printf("%" PRId64 "\n", SystemNative_GetBootTimeTicks());
    return 0;
}

(SystemNative_GetBootTimeTicks is the current state of that function in PR)

@steveisok steveisok added this to the 8.0.0 milestone Jul 25, 2022
@adamsitnik
Copy link
Member

adamsitnik commented Jul 27, 2022

thanks for the ping. #67589 needs device testing on Android. I

@steveisok is there any chance you could help @am11 with the Android debugging?

@danmoseley
Copy link
Member

@steveisok ?

@danmoseley
Copy link
Member

@steveisok 🙂

@steveisok
Copy link
Member

Sorry, yes, we can help with this one.

@steveisok
Copy link
Member

@simonrozsival can you please help out with this one?

@simonrozsival
Copy link
Member

@am11 I tested the code on my device with API 32 and on emulators with API 21 and 24 and it worked well on all of these levels. It seems to me that the only problem with the PR is that you're checking TARGET_LINUX and not TARGET_ANDROID.

@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Sep 8, 2022
@adamsitnik
Copy link
Member

@simonrozsival thank you for your help!

@ghost ghost locked as resolved and limited conversation to collaborators Oct 8, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants