-
Notifications
You must be signed in to change notification settings - Fork 0
add gomobile test2 #2
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| // Package libwallet exports Decred wallet functionalities for mobile platforms. | ||
| // This package is designed to be compiled with gomobile for iOS and Android. | ||
| // | ||
| // Build examples: | ||
| // | ||
| // gomobile bind -target=android -androidapi=23 -o ./build/libwallet.aar ./gomobile | ||
| // gomobile bind -target=ios -o ./build/Libwallet.xcframework ./gomobile | ||
| package libwallet | ||
|
|
||
| import ( | ||
| "context" | ||
| "errors" | ||
| "fmt" | ||
| "sync" | ||
|
|
||
| "github.com/decred/libwallet/assetlog" | ||
| "github.com/decred/libwallet/dcr" | ||
| "github.com/decred/slog" | ||
| ) | ||
|
|
||
| // ----------------------------------------------------------------------------- | ||
| // Global variables (shared across files in this package) x | ||
| // ----------------------------------------------------------------------------- | ||
|
|
||
| var ( | ||
| mainCtx context.Context | ||
| cancelMainCtx context.CancelFunc | ||
| wg sync.WaitGroup | ||
|
|
||
| logBackend *parentLogger | ||
|
Check failure on line 30 in gomobile/gomobile.go
|
||
| logMtx sync.RWMutex | ||
| log slog.Logger | ||
|
|
||
| // walletsMtx protects wallets and initialized. | ||
| walletsMtx sync.RWMutex | ||
| wallets = make(map[string]*wallet) | ||
|
Check failure on line 36 in gomobile/gomobile.go
|
||
| initialized bool | ||
| ) | ||
|
|
||
| // ----------------------------------------------------------------------------- | ||
| // Core Functions | ||
| // ----------------------------------------------------------------------------- | ||
|
|
||
| // Initialize initializes the libwallet mobile library. | ||
| func Initialize(logDir, logLvl string) (string, error) { | ||
| walletsMtx.Lock() | ||
| defer walletsMtx.Unlock() | ||
| if initialized { | ||
| return "", errors.New("duplicate initialization") | ||
| } | ||
|
|
||
| lvl, ok := slog.LevelFromString(logLvl) | ||
| if !ok { | ||
| return "", fmt.Errorf("unknown log level %q", logLvl) | ||
| } | ||
|
|
||
| if logDir != "" { | ||
| logSpinner, err := assetlog.NewRotator(logDir, "dcrwallet.log") | ||
| if err != nil { | ||
| return "", fmt.Errorf("error initializing log rotator: %v", err) | ||
| } | ||
|
|
||
| logBackend = newParentLogger(logSpinner, lvl) | ||
|
Check failure on line 63 in gomobile/gomobile.go
|
||
| err = dcr.InitGlobalLogging(logDir, logBackend, lvl) | ||
| if err != nil { | ||
| return "", fmt.Errorf("error initializing logger for external pkgs: %v", err) | ||
| } | ||
| } else { | ||
| logBackend = newParentStdOutLogger(lvl) | ||
|
Check failure on line 69 in gomobile/gomobile.go
|
||
| } | ||
|
|
||
| logMtx.Lock() | ||
| log = logBackend.SubLogger("APP") | ||
| logMtx.Unlock() | ||
|
|
||
| mainCtx, cancelMainCtx = context.WithCancel(context.Background()) | ||
|
|
||
| initialized = true | ||
| return "libwallet mobile initialized", nil | ||
| } | ||
|
|
||
| // Shutdown shuts down the libwallet mobile library. | ||
| func Shutdown() (string, error) { | ||
| walletsMtx.Lock() | ||
| defer walletsMtx.Unlock() | ||
| if !initialized { | ||
| return "", errors.New("not initialized") | ||
| } | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [WARNING] RLock held during potentially slow operation. Current: Consider: If logging is fast and non-blocking in this implementation, this may be acceptable. However, best practice is to minimize lock duration. Suggested pattern (if needed): logMtx.RLock()
logger := log
logMtx.RUnlock()
logger.Debug("libwallet mobile shutting down")Why: Avoid holding locks during I/O operations to prevent blocking other goroutines. |
||
| logMtx.RLock() | ||
| log.Debug("libwallet mobile shutting down") | ||
| logMtx.RUnlock() | ||
|
|
||
| for _, w := range wallets { | ||
| if err := w.CloseWallet(); err != nil { | ||
| w.log.Errorf("close wallet error: %v", err) | ||
| } | ||
| } | ||
| wallets = make(map[string]*wallet) | ||
|
Check failure on line 99 in gomobile/gomobile.go
|
||
|
|
||
| // Stop all remaining background processes and wait for them to stop. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [CRITICAL] Potential deadlock: Context cancellation with mutex held. Current: walletsMtx.Lock()
defer walletsMtx.Unlock()
// ...
cancelMainCtx()
wg.Wait()Issue: If any goroutine in Suggested: walletsMtx.Lock()
// ... close wallets ...
walletsMtx.Unlock()
// Cancel and wait AFTER releasing the mutex
cancelMainCtx()
wg.Wait()
logMtx.Lock()
// ... close logger ...Why: Background goroutines must be able to acquire locks during shutdown. Holding locks during |
||
| cancelMainCtx() | ||
| wg.Wait() | ||
|
|
||
| // Close the logger backend as the last step. | ||
| logMtx.Lock() | ||
| log.Debug("libwallet mobile shutdown") | ||
| _ = logBackend.Close() | ||
| logBackend = nil | ||
| logMtx.Unlock() | ||
|
|
||
| initialized = false | ||
| return "libwallet mobile shutdown", nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[SUGGESTION] Initialization order could be improved.
Current: Context created after setting
initialized = trueflag (line 77).Suggested: Move
mainCtx, cancelMainCtx = context.WithCancel(context.Background())to before settinginitialized = true(around line 75).Why: If initialization is checked between line 77 and 76, the context might not be ready. Minor race condition.