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

Port Android APEX timezone location lookup from mono/mono #41867

Closed
akoeplinger opened this issue Sep 4, 2020 · 1 comment · Fixed by #54845
Closed

Port Android APEX timezone location lookup from mono/mono #41867

akoeplinger opened this issue Sep 4, 2020 · 1 comment · Fixed by #54845
Assignees
Milestone

Comments

@akoeplinger
Copy link
Member

We need to port mono/mono#20349 and verify it works.

@akoeplinger akoeplinger added this to the 6.0.0 milestone Sep 4, 2020
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Sep 4, 2020
@akoeplinger akoeplinger removed the untriaged New issue has not been triaged by the area owner label Sep 4, 2020
@akoeplinger
Copy link
Member Author

It also looks like Android will remove the zone.tab file aosp-mirror/platform_bionic@2b76a94

So we likely can't use the existing TimeZoneInfo.Unix.cs as is and need to port the https://github.com/mono/mono/blob/master/mcs/class/corlib/System/TimeZoneInfo.Android.cs

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jun 2, 2021
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Jun 15, 2021
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jun 28, 2021
steveisok pushed a commit that referenced this issue Jul 21, 2021
Fixes #41867

Android has removed zone.tab, so TimeZoneInfo.Unix.cs will no longer work properly on Android as GetTimeZoneIds directly depends on the zone.tab file. The chain of dependency is as follows
 
GetSystemTimeZones -> PopulateAllSystemTimeZones -> GetTimeZoneIds -> zone.tab
                TZI.cs                                  TZI.Unix.cs                        TZI.Unix.cs         TZI.Unix.cs
 Where TZI is TimeZoneInfo

zone.tab is a file that is found on the unix system under /usr/share/zoneinfo/
GetTimeZoneIds reads zone.tab to obtain the TimeZoneId in that file
PopulateAllSystemTimeZones caches all the TimeZone Ids in cachedData
GetSystemTimeZones returns a ReadOnlyCollection containing all valid TimeZone’s from the local machine, and the entries are sorted by their DisplayName. It relies on cachedData._systemTimeZones being populated.

The problem is that the time zone data for Android can be found in the file tzdata at the possible locations

/apex/com.android.tzdata/etc/tz/tzdata
/apex/com.android.runtime/etc/tz/tzdata
/data/misc/zoneinfo/tzdata
/system/usr/share/zoneinfo/tzdata

The rest of unix the time zone data can be found in the file zone.tab at

 /usr/share/zoneinfo/zone.tab
Android's TimeZoneInfo implementation should read time zone data from its locations instead of the general /usr/share/zoneinfo/zone.tab path. Moreover, tzdata contains all timezones byte data.

This PR achieves the following:

1. Splits TimeZoneInfo.Unix.cs into TimeZoneInfo.Unix.cs, TimeZoneInfo.Unix.NonAndroid.cs (non-Android), and 
    TimeZoneInfo.Unix.Android.cs (Android specific)
2. Adds an interop to obtain the default time zone on Android based on persist.sys.timezone
3. Implements GetLocalTimeZoneCore TryGetTimeZoneFromLocalMachineCore and GetTimeZoneIds for Android 
    based on mono/mono implementation 
    https://github.com/mono/mono/blob/main/mcs/class/corlib/System/TimeZoneInfo.Android.cs
4. Adds new string resources to throw exceptions
5. Refactors the mono/mono implementation of parsing tzdata

Android tzdata files are found in the format of
Header <Beginning of Entry Index> Entry Entry Entry ... Entry <Beginning of Data Index> <TZDATA>

https://github.com/aosp-mirror/platform_bionic/blob/master/libc/tzcode/bionic.cpp

The header (24 bytes) contains the following information
signature - 12 bytes of the form "tzdata2012f\0" where 2012f is subject to change
index offset - 4 bytes that denotes the offset at which the index of the tzdata file starts
data offset - 4 bytes that denotes the offset at which the data of the tzdata file starts
final offset - 4 bytes that used to denote the final offset, which we don't use but will note.

Each Data Entry (52 bytes) can be used to generate a TimeZoneInfo and contain the following information
id - 40 bytes that contain the id of the time zone data entry timezone<id>
byte offset - 4 bytes that denote the offset from the data offset timezone<id> data can be found
length - 4 bytes that denote the length of the data for timezone<id>
unused - 4 bytes that used to be raw GMT offset, but now is always 0 since tzdata2014f (L).

When GetLocalTimeZoneCore TryGetTimeZoneFromLocalMachineCore or GetTimeZoneIds are called, an android timezone data instance is instantiated and loaded by attempting to load a tzdata file that can be found at four locations mentioned earlier. The file is parsed by first loading the header which contains information about where the data index and data begin. The data index is then parsed to obtain the timezone and the corresponding bytes location in the file to fill the three arrays _ids _byteOffsets _lengths. These arrays are referenced to obtain the corresponding byte data for a timezone, and functions from TimeZoneInfo.Unix.cs are leveraged to create a TimeZoneInfo from there.
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Jul 21, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Aug 20, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
4 participants